#include <memory>
#include <cassert>
#include "SQLStatementParser.h"
#include "OdpsSelectParser.h"
#include "SQLExprParser.h"
#include "SQLCreateTableParser.h"
#include "SQLSelectListCache.h"
#include "SQLInsertValueHandler.h"
#include "SQLParserUtils.h"
#include "../../utils/instanceof.h"
#include "../../utils/FnvHash.h"
#include "../../utils/StringUtils.h"
#include "../../utils/common_ptr.h"
#include "../dialect/mysql/ast/statement/MySqlHintStatement.h"
#include "../dialect/mysql/ast/statement/MySqlUpdatePlanCacheStatement.h"
#include "../dialect/mysql/ast/statement/MysqlDropFullTextStatement.h"
#include "../dialect/mysql/ast/statement/MySqlManageInstanceGroupStatement.h"
#include "../dialect/mysql/ast/statement/MySqlExplainPlanCacheStatement.h"
#include "../dialect/mysql/parser/MySqlExprParser.h"
#include "../ast/statement/SQLSelectStatement.h"
#include "../ast/statement/SQLInsertStatement.h"
#include "../ast/statement/SQLUpdateStatement.h"
#include "../ast/statement/SQLUpdateSetItem.h"
#include "../ast/statement/SQLTruncateStatement.h"
#include "../ast/statement/SQLDropTableStatement.h"
#include "../ast/statement/SQLDropUserStatement.h"
#include "../ast/statement/SQLDropIndexStatement.h"
#include "../ast/statement/SQLDropViewStatement.h"
#include "../ast/statement/SQLDropTriggerStatement.h"
#include "../ast/statement/SQLDropDatabaseStatement.h"
#include "../ast/statement/SQLDropFunctionStatement.h"
#include "../ast/statement/SQLDropTableSpaceStatement.h"
#include "../ast/statement/SQLDropProcedureStatement.h"
#include "../ast/statement/SQLDropSequenceStatement.h"
#include "../ast/statement/SQLDropEventStatement.h"
#include "../ast/statement/SQLDropResourceStatement.h"
#include "../ast/statement/SQLDropResourceGroupStatement.h"
#include "../ast/statement/SQLDropLogFileGroupStatement.h"
#include "../ast/statement/SQLDropServerStatement.h"
#include "../ast/statement/SQLDropTableGroupStatement.h"
#include "../ast/statement/SQLDropRoleStatement.h"
#include "../ast/statement/SQLDropOutlineStatement.h"
#include "../ast/statement/SQLDropCatalogStatement.h"
#include "../ast/statement/SQLDropMaterializedViewStatement.h"
#include "../ast/statement/SQLDropOfflineModelStatement.h"
#include "../ast/statement/SQLRevokeStatement.h"
#include "../ast/statement/SQLObjectType.h"
#include "../ast/statement/SQLPrivilegeItem.h"
#include "../ast/statement/SQLRollbackStatement.h"
#include "../ast/statement/SQLUseStatement.h"
#include "../ast/statement/SQLSetStatement.h"
#include "../ast/statement/SQLDeleteStatement.h"
#include "../ast/statement/SQLExplainStatement.h"
#include "../ast/statement/SQLCallStatement.h"
#include "../ast/statement/SQLMergeStatement.h"
#include "../ast/statement/SQLErrorLoggingClause.h"
#include "../ast/statement/SQLRefreshMaterializedViewStatement.h"
#include "../ast/statement/SQLFetchStatement.h"
#include "../ast/statement/SQLGrantStatement.h"
#include "../ast/statement/SQLCommentStatement.h"
#include "../ast/statement/SQLOpenStatement.h"
#include "../ast/statement/SQLCloseStatement.h"
#include "../ast/statement/SQLAlterIndexStatement.h"
#include "../ast/statement/SQLAlterSequenceStatement.h"
#include "../ast/statement/SQLAlterTableAddColumn.h"
#include "../ast/statement/SQLAlterTableRenameColumn.h"
#include "../ast/statement/SQLAlterTableRename.h"
#include "../ast/statement/SQLAlterTableRenameConstraint.h"
#include "../ast/statement/SQLPartitionRef.h"
#include "../ast/expr/SQLIdentifierExpr.h"
#include "../ast/expr/SQLDecimalExpr.h"
#include "../ast/expr/SQLNullExpr.h"
#include "../dialect/mysql/ast/statement/MySqlSelectQueryBlock.h"

#include "../../utils/listAddAll.h"
#include "../../utils/log.h"
#include "../../utils/common_ptr.h"
#include "../../utils/BigDecimal.h"
#include "../../utils/MySqlUtils.h"
#include "../../utils/UUID.h"
#include "../../utils/encode_util.h"

SQLStatementParser::SQLStatementParser()
{
}

SQLStatementParser::~SQLStatementParser()
{
  // for (std::list<SQLStatement_ptr >::iterator it = statementList->begin(); it != statementList->end(); ++it)
  // {
  //   if (instanceof <SQLStatement, SQLTruncateStatement>(*it))
  //   {
  //     SQLTruncateStatement_ptr x2 = std::dynamic_pointer_cast<SQLTruncateStatement>(*it);
  //     if (x2)
  //     {
  //       delete x2;
  //     }
  //   }
  //   else if (instanceof <SQLStatement, SQLUpdateStatement>(*it))
  //   {
  //     auto x2 = dynamic_cast<SQLUpdateStatement *>(*it);
  //     if (x2)
  //     {
  //       delete x2;
  //     }
  //   }
  //   else
  //   {
  //     delete *it;
  //   }
  // }
  // statementList->clear();

  // for (std::list<SQLStatement_ptr  >::iterator it = yaList->begin(); it != yaList->end(); ++it)
  // {
  //   // std::cout << __FILE__ << ": " << __LINE__ << ", in SQLStatementParser::~SQLStatementParser, destructor step 1.2";
  //   delete *it;
  // }
  // yaList->clear();

  // if (exprParserHere && this->exprParser != NULL)
  // {
  //   // std::cout << __FILE__ << ": " << __LINE__ << ", in SQLStatementParser::~SQLStatementParser, destructor step 2.1";
  //   delete exprParser;
  // }
  // std::cout << __FILE__ << ": " << __LINE__ << ", in SQLStatementParser::~SQLStatementParser, destructor step 3";
}

// SQLStatementParser::SQLStatementParser(string_ptr theSql) : exprParser(new SQLExprParser(theSql)), super(exprParser->getLexer()),  exprParserHere(BOOL::TRUE){
// SQLStatementParser::SQLStatementParser(string_ptr theSql) : super(theSql), exprParser(new SQLExprParser(getLexer())), exprParserHere(BOOL::TRUE)
SQLStatementParser::SQLStatementParser(string_ptr theSql)
    : SQLStatementParser(SQLExprParser_ptr(new SQLExprParser(theSql)))
{
  // auto tmp = DbType();
  // SQLStatementParser(theSql, tmp);
  // LOG_INFO << "I am INFO!";
  // std::cout << __FILE__ << ": " << __LINE__ << ", in SQLStatementParser::SQLStatementParser, constructor 1 ";
  LOG_INFO << lexer->token()->get_index() << ":" << lexer->token()->getName()->c_str() << ",stringVal:" << lexer->stringVal()->c_str() << ", pos " << lexer->pos();
  // std::cout << __FILE__ << ": " << __LINE__ << ", in SQLStatementParser::parseStatementList, " << stream1.str();
  // this(new SQLExprParser(theSql));
  // this->exprParser = new SQLExprParser(theSql);
  // super(this->exprParser->getLexer());
  // exprParserHere = BOOL::TRUE;
}

SQLStatementParser::SQLStatementParser(string_ptr sql, DbType_ptr dbType)
    : SQLStatementParser(SQLExprParser_ptr(new SQLExprParser(sql, dbType)))
{
}

SQLStatementParser::SQLStatementParser(SQLExprParser_ptr theExprParser)
    : SQLParser(theExprParser->getLexer(), theExprParser->dbType),
      exprParser(theExprParser),
      exprParserHere(BOOL::FALSE)
{
  LOG_INFO << "dbType->name:" << dbType->name->c_str();
  // super(theExprParser->getLexer());
  // this->theExprParser = theExprParser;
  statementList = std::make_shared<std::list<SQLStatement_ptr>>();
  yaList = std::make_shared<std::list<SQLStatement_ptr>>();
  parseCompleteValues = BOOL::TRUE;
  parseValuesSize = 3;
}

SQLExprParser_ptr SQLStatementParser::getExprParser()
{
  return exprParser;
}

SQLStatement_list_ptr SQLStatementParser::parseStatementList()
{
  LOG_INFO << "lexer->token->name:" << lexer->token()->getName();
  parseStatementList(statementList);
  LOG_INFO << "lexer->token->name:" << lexer->token()->getName();
  return statementList;
}

void SQLStatementParser::parseStatementList(SQLStatement_list_ptr theStatementList)
{
  LOG_INFO << "lexer->token->name:" << lexer->token()->getName();
  parseStatementList(theStatementList, -1);
  LOG_INFO << "lexer->token->name:" << lexer->token()->getName();
}

void SQLStatementParser::parseStatementList(SQLStatement_list_ptr theStatementList, int max)
{
  LOG_INFO << "lexer->token->name:" << lexer->token()->getName();
  parseStatementList(statementList, max, NULL);
  LOG_INFO << "lexer->token->name:" << lexer->token()->getName();
}

void SQLStatementParser::parseStatementList(SQLStatement_list_ptr statementList, int max, SQLObject_ptr parent)
{
  LOG_INFO << "token_ index:" << this->lexer->token_->index;
  LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str();
  if ((L"select @@session.tx_read_only" == lexer->getSource().c_str()) &&
      lexer->token()->name->c_str() == Token::SELECT.name->c_str())
  {
    LOG_INFO << ":";
    SQLSelect_ptr select = SQLSelect_ptr(new SQLSelect());
    MySqlSelectQueryBlock_ptr queryBlock = MySqlSelectQueryBlock_ptr(new MySqlSelectQueryBlock());
    queryBlock->addSelectItem(SQLPropertyExpr_ptr(new SQLPropertyExpr(SQLVariantRefExpr_ptr(new SQLVariantRefExpr("@@session")), make_string_ptr("tx_read_only"))));
    select->setQuery(queryBlock);

    SQLSelectStatement_ptr stmt = SQLSelectStatement_ptr(new SQLSelectStatement(select));
    statementList->push_back(stmt);

    lexer->reset(29, '\u001A', Token_ptr(new Token(&Token::XEOF)));
    return;
  }

  BOOL_ptr semi = BOOL::FALSE;
  for (int i = 0;; i++)
  {
    LOG_INFO << "i:" << i;
    if (max != -1)
    {
      if (statementList->size() >= max)
      {
        return;
      }
    }
    LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str();
    while (lexer->token()->name->c_str() == Token::MULTI_LINE_COMMENT.name->c_str() ||
           lexer->token()->name->c_str() == Token::LINE_COMMENT.name->c_str())
    {
      lexer->nextToken();
    }

    string_ptr token_name = lexer->token()->getName();
    if (token_name != nullptr)
    {
      LOG_INFO << "token name:" << token_name->c_str();
    }
    wstring_ptr stringVal = lexer->stringVal();
    if (stringVal != nullptr)
    {
      LOG_INFO << "lexer text:" << encode_util::UnicodeToUTF8(*stringVal).c_str();
    }

    LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str();
    if (lexer->token()->name->c_str() == Token::XEOF.name->c_str() ||
        lexer->token()->name->c_str() == Token::END.name->c_str() ||
        lexer->token()->name->c_str() == Token::UNTIL.name->c_str() ||
        lexer->token()->name->c_str() == Token::ELSE.name->c_str() ||
        lexer->token()->name->c_str() == Token::WHEN.name->c_str())
    {
      if (lexer->isKeepComments() && lexer->hasComment() && statementList->size() > 0)
      {
        auto it_statementList = statementList->begin();
        std::advance(it_statementList, statementList->size() - 1);
        SQLStatement_ptr stmt = (*it_statementList);
        stmt->addAfterComment(lexer->readAndResetComments());
      }
      return;
    }
    else if (lexer->token()->name->c_str() == Token::SEMI.name->c_str())
    {
      int line0 = lexer->getLine();
      wchar_t ch = lexer->ch;
      lexer->nextToken();
      int line1 = lexer->getLine();

      if (statementList->size() > 0)
      {
        auto it_statementList = statementList->begin();
        std::advance(it_statementList, statementList->size() - 1);
        SQLStatement_ptr lastStmt = (*it_statementList);
        lastStmt->setAfterSemi(BOOL::TRUE);

        if (lexer->isKeepComments())
        {
          if (ch == L'\n' &&
              !lexer->getComments()->empty() &&
              !lexer->getComments()->empty() &&
              !(instanceof <SQLStatement, SQLSetStatement>(lastStmt)))
          {
            std::wstring tmp = L"";
            tmp += L'\n';
            lexer->getComments()->push_front(make_wstring_ptr(tmp));
          }

          if (line1 - line0 <= 1)
          {
            lastStmt->addAfterComment(lexer->readAndResetComments());
          }
        }
      }

      semi = BOOL::TRUE;

      continue;
    }
    else if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
    {
      SQLStatement_ptr stmt = parseWith();
      stmt->setParent(parent);
      statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::SELECT.name->c_str())
    {
      MySqlHintStatement_ptr hintStatement = NULL;
      auto it_statementList = statementList->begin();
      std::advance(it_statementList, statementList->size() - i);
      LOG_INFO << "i:" << i << ",statementList->size:" << statementList->size();
      if (i == 1 &&
              statementList->size() > 0 &&
          instanceof <SQLStatement, MySqlHintStatement>(*it_statementList))
      {
        hintStatement = std::dynamic_pointer_cast<MySqlHintStatement>(*it_statementList);
      }
      else if (i > 0 &&
               !(dbType->name->c_str() == DbType::odps.name->c_str()) &&
               !semi)
      {
        std::string tmp = "syntax error. ";
        tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
        throw new ParserException(make_string_ptr(tmp));
      }

      LOG_INFO << "goto parseSelect";
      SQLStatement_ptr stmt = parseSelect();
      if (stmt != nullptr)
      {
        stmt->setParent(parent);
        if (hintStatement != NULL && instanceof <SQLStatement, SQLStatementImpl>(stmt))
        {
          SQLStatementImpl_ptr stmtImpl = std::dynamic_pointer_cast<SQLStatementImpl>(stmt);
          SQLCommentHint_list_ptr hints = stmtImpl->getHeadHintsDirect();
          if (hints->empty())
          {
            stmtImpl->setHeadHints(hintStatement->getHints());
          }
          else
          {
            // hints.addAll(hintStatement.getHints());
            for (auto it : *hintStatement->getHints())
            {
              hints->push_back(it);
            }
          }
          // statementList->set(statementList->size() - 1, stmt);
          (*it_statementList) = stmt;
        }
        else
        {
          statementList->push_back(stmt);
        }
      }
      semi = BOOL::FALSE;
      if (i > 0)
      {
        assert(false);
      }
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::UPDATE.name->c_str())
    {
      // FOR ADS
      Lexer_SavePoint_ptr savePoint = lexer->mark();
      lexer->nextToken();
      if (dbType->name->c_str() == DbType::mysql.name->c_str() &&
          lexer->identifierEquals(L"PLANCACHE"))
      {
        lexer->nextToken();
        if (lexer->token()->name->c_str() == Token::SELECT.name->c_str())
        {
          MySqlUpdatePlanCacheStatement_ptr stmt = MySqlUpdatePlanCacheStatement_ptr(new MySqlUpdatePlanCacheStatement());

          SQLSelect_ptr fromSelect = createSQLSelectParser()->select();
          accept(Token::TO);
          SQLSelect_ptr toSelect = createSQLSelectParser()->select();

          stmt->setFormSelect(fromSelect);
          stmt->setToSelect(toSelect);

          statementList->push_back(stmt);
          continue;
        }
      }

      lexer->reset(savePoint);
      SQLStatement_ptr stmt = SQLStatement_ptr(parseUpdateStatement());
      stmt->setParent(parent);
      statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::CREATE.name->c_str())
    {
      LOG_INFO << ":";
      SQLStatement_ptr stmt = parseCreate();
      stmt->setParent(parent);
      statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::INSERT.name->c_str())
    {
      LOG_INFO << "goto parseInsert";
      SQLStatement_ptr stmt = parseInsert();
      if (stmt != NULL)
      {
        LOG_INFO << "stmt not NULL";
        stmt->setParent(parent);
      }
      else
      {
        LOG_INFO << ": stmt == NULL";
        assert(stmt != nullptr);
      }
      LOG_INFO << " push_back";
      statementList->push_back(stmt);
      LOG_INFO << "return";
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::DELETE.name->c_str())
    {
      SQLStatement_ptr stmt = parseDeleteStatement();
      stmt->setParent(parent);
      statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::EXPLAIN.name->c_str())
    {
      lexer->computeRowAndColumn();
      int sourceLine = lexer->posLine;
      int sourceColumn = lexer->posColumn;

      // FOR ADS
      Lexer_SavePoint_ptr savePoint = lexer->mark();
      lexer->nextToken();

      if (lexer->identifierEquals(L"PLANCACHE"))
      {
        lexer->nextToken();
        MySqlExplainPlanCacheStatement_ptr stmt = MySqlExplainPlanCacheStatement_ptr(new MySqlExplainPlanCacheStatement());
        stmt->setSourceLine(sourceLine);
        stmt->setSourceLine(sourceColumn);
        statementList->push_back(stmt);
      }
      else
      {
        lexer->reset(savePoint);
        SQLExplainStatement_ptr stmt = parseExplain();
        stmt->setSourceLine(sourceLine);
        stmt->setSourceLine(sourceColumn);
        stmt->setParent(parent);
        statementList->push_back(stmt);
      }
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::SET.name->c_str())
    {
      SQLStatement_ptr stmt = parseSet();
      stmt->setParent(parent);
      statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::ALTER.name->c_str())
    {
      SQLStatement_ptr stmt = parseAlter();
      stmt->setParent(parent);
      statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::TRUNCATE.name->c_str())
    {
      LOG_INFO << "goto parseTruncate";
      SQLStatement_ptr stmt = parseTruncate();
      LOG_INFO << "goto setParent";
      stmt->setParent(parent);
      LOG_INFO << "goto push_back";
      statementList->push_back(stmt);
      LOG_INFO << "statementList size:" << statementList->size();
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::USE.name->c_str())
    {
      SQLUseStatement_ptr stmt = SQLUseStatement_ptr(parseUse());
      stmt->setParent(parent);
      statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::GRANT.name->c_str())
    {
      SQLStatement_ptr stmt = parseGrant();
      stmt->setParent(parent);
      statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::REVOKE.name->c_str())
    {
      SQLRevokeStatement_ptr stmt = parseRevoke();
      stmt->setParent(parent);
      statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::SHOW.name->c_str())
    {
      SQLStatement_ptr stmt = parseShow();
      stmt->setParent(parent);
      statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::MERGE.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseMerge();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::REPEAT.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseRepeat();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::DECLARE.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseDeclare();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::WHILE.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseWhile();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::IF.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseIf();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::CASE.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseCase();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::OPEN.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseOpen();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::FETCH.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseFetch();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::DROP.name->c_str())
    {
      SQLStatement_ptr stmt = parseDrop();
      stmt->setParent(parent);
      statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseComment();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::KILL.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseKill();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::CLOSE.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseClose();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::RETURN.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseReturn();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::UPSERT.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseUpsert();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::LEAVE.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseLeave();
      //   stmt->setParent(parent);
      //   statementList->push_back(stmt);
      continue;
    }

    LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str();
    WLOG_INFO << L"lexer->stringVal_:" << lexer->stringVal_.c_str();
    if (lexer->token()->name->c_str() == Token::LBRACE.name->c_str() ||
        lexer->identifierEquals(L"CALL"))
    {
      SQLCallStatement_ptr stmt = parseCall();
      //   statementList->push_back(stmt);
      continue;
    }

    if (lexer->identifierEquals(L"UPSERT"))
    {
      //   SQLStatement_ptr  stmt = parseUpsert();
      //   statementList->push_back(stmt);
      continue;
    }

    if (lexer->identifierEquals(L"LIST"))
    {
      Lexer_SavePoint_ptr mark = lexer->mark();

      // SQLStatement_ptr  stmt = parseList();
      // if (stmt != NULL)
      // {
      //   statementList->push_back(stmt);
      //   continue;
      // }
      // else
      // {
      //   lexer->reset(mark);
      // }
    }

    if (lexer->identifierEquals(L"RENAME"))
    {
      SQLStatement_ptr stmt = parseRename();
      statementList->push_back(stmt);
      continue;
    }

    if (lexer->identifierEquals(L"RELEASE"))
    {
      SQLStatement_ptr stmt = parseReleaseSavePoint();
      statementList->push_back(stmt);
      continue;
    }

    if (lexer->identifierEquals(L"SAVEPOINT"))
    {
      SQLStatement_ptr stmt = parseSavePoint();
      statementList->push_back(stmt);
      continue;
    }

    if (lexer->identifierEquals(L"REFRESH"))
    {
      // SQLStatement_ptr  stmt = parseRefresh();
      // statementList->push_back(stmt);
      continue;
    }

    if (lexer->identifierEquals(L"SETPROJECT"))
    {
      SQLStatement_ptr stmt = parseSet();
      statementList->push_back(stmt);
      continue;
    }

    if (lexer->identifierEquals(FnvHash::Constants::COPY))
    {
      // SQLStatement_ptr  stmt = parseCopy();
      // statementList->push_back(stmt);
      continue;
    }

    if (lexer->token()->name->c_str() == Token::DESC.name->c_str() ||
        lexer->identifierEquals(FnvHash::Constants::DESCRIBE))
    {
      // SQLStatement_ptr  stmt = parseDescribe();
      // statementList->push_back(stmt);
      continue;
    }

    if (lexer->identifierEquals(L"ROLLBACK"))
    {
      // SQLStatement_ptr  stmt = parseRollback();
      // statementList->push_back(stmt);

      // if (parent instanceof SQLBlockStatement && DbType::mysql == dbType)
      // {
      //   return;
      // }

      continue;
    }

    if (lexer->identifierEquals(L"DUMP"))
    {
      // SQLStatement_ptr  stmt = parseDump();
      // statementList->push_back(stmt);

      continue;
    }

    if (lexer->identifierEquals(FnvHash::Constants::COMMIT))
    {
      SQLStatement_ptr stmt = parseCommit();

      statementList->push_back(stmt);

      // if (parent instanceof SQLBlockStatement && DbType::mysql == dbType)
      // {
      //   return;
      // }

      continue;
    }

    if (lexer->identifierEquals(FnvHash::Constants::RETURN))
    {
      //   SQLStatement_ptr  stmt = parseReturn();
      //   statementList->push_back(stmt);
      continue;
    }

    if (lexer->identifierEquals(FnvHash::Constants::PURGE))
    {
      //   SQLStatement_ptr  stmt = parsePurge();
      //   statementList->push_back(stmt);
      continue;
    }

    if (lexer->identifierEquals(FnvHash::Constants::FLASHBACK))
    {
      //   SQLStatement_ptr  stmt = parseFlashback();
      //   statementList->push_back(stmt);
      continue;
    }

    if (lexer->identifierEquals(FnvHash::Constants::WHO))
    {
      //   SQLStatement_ptr  stmt = parseWhoami();
      //   statementList->push_back(stmt);
      continue;
    }

    if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
    {
      //   SQLStatement_ptr  stmt = parseFor();
      //   statementList->push_back(stmt);
      //   stmt->setParent(parent);
      continue;
    }

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      Lexer_SavePoint_ptr savePoint = lexer->markOut();

      int parenCount = 0;
      do
      {
        lexer->nextToken();
        parenCount++;
      } while (lexer->token()->name->c_str() == Token::LPAREN.name->c_str());

      if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str() &&
          parenCount == 1 && dbType->name->c_str() == DbType::odps.name->c_str())
      {
        lexer->nextToken();
        continue;
      }

      if (lexer->token()->name->c_str() == Token::SELECT.name->c_str())
      {
        lexer->reset(savePoint);
        // SQLStatement_ptr  stmt = parseSelect();
        // statementList->push_back(stmt);
        continue;
      }
      else
      {
        std::string tmp = "TODO ";
        tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
        throw new ParserException(make_string_ptr(tmp));
      }
    }

    if (lexer->token()->name->c_str() == Token::VALUES.name->c_str())
    {
      // SQLValuesTableSource* values = this->createSQLSelectParser().parseValues();
      // SQLSelectStatement* stmt = new SQLSelectStatement();
      // stmt->setSelect(new SQLSelect(values));
      // statementList->push_back(stmt);
      // stmt->setParent(parent);
      continue;
    }

    if (lexer->identifierEquals(L"OPTIMIZE"))
    {
      // SQLStatement_ptr  stmt = parseOptimize();
      // statementList->push_back(stmt);
      // stmt->setParent(parent);
      continue;
    }

    int size = statementList->size();
    LOG_INFO << "goto parseStatementListDialect";
    if (parseStatementListDialect(statementList))
    {
      if (parent != NULL)
      {
        LOG_INFO << "statementList->size:" << statementList->size();
        for (int j = size; j < statementList->size(); ++j)
        {
          // SQLStatement dialectStmt = statementList->get(j);
          // dialectStmt.setParent(parent);
        }
      }

      continue;
    }

    std::string tmp = "not supported.";
    tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
    throw new ParserException(make_string_ptr(tmp));
  }
}

SQLStatement_ptr SQLStatementParser::parseRollback()
{

  // LOG_INFO << ", in SQLStatementParser::parseRollback, step 1";
  lexer->nextToken();

  if (identifierEquals("WORK"))
  {
    lexer->nextToken();
  }

  SQLRollbackStatement_ptr stmt = SQLRollbackStatement_ptr(new SQLRollbackStatement());

  if (lexer->token()->name->c_str() == Token::TO.name->c_str())
  {
    lexer->nextToken();

    if (identifierEquals("SAVEPOINT"))
    {
      lexer->nextToken();
    }

    stmt->setTo(this->exprParser->getName());
  }
  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseCommit()
{

  std::stringstream stream;
  stream << "TODO " << lexer->token()->getName()->c_str() << " " << lexer->stringVal()->c_str();
  throw new ParserException(make_string_ptr(stream.str()));
}

SQLStatement_ptr SQLStatementParser::parseShow()
{
  std::stringstream stream;
  stream << "TODO " << lexer->token()->getName()->c_str() << " " << lexer->stringVal()->c_str();
  throw new ParserException(make_string_ptr(stream.str()));
}

SQLUseStatement_ptr SQLStatementParser::parseUse()
{
  LOG_INFO << ", in SQLStatementParser::parseUse, step 1";
  accept(Token::USE);
  SQLUseStatement_ptr stmt = SQLUseStatement_ptr(new SQLUseStatement());
  stmt->setDatabase(this->exprParser->getName());
  return stmt;
}

SQLGrantStatement_ptr SQLStatementParser::parseGrant()
{
  accept(Token::GRANT);
  SQLGrantStatement_ptr stmt = SQLGrantStatement_ptr(new SQLGrantStatement(getDbType()));

  parsePrivileages(stmt->getPrivileges(), stmt);

  if (lexer->token()->name->c_str() == Token::ON.name->c_str())
  {
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::PROCEDURE.name->c_str())
    {
      lexer->nextToken();
      stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::PROCEDURE)));
      // break;
    }
    else if (lexer->token()->name->c_str() == Token::FUNCTION.name->c_str())
    {
      lexer->nextToken();
      stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::FUNCTION)));
      // break;
    }
    else if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
    {
      lexer->nextToken();
      stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::TABLE)));
      // break;
    }
    else if (lexer->token()->name->c_str() == Token::USER.name->c_str())
    {
      lexer->nextToken();
      stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::USER)));
      // break;
    }
    else if (lexer->token()->name->c_str() == Token::DATABASE.name->c_str())
    {
      lexer->nextToken();
      stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::DATABASE)));
      // break;
    }
    else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      if (lexer->identifierEquals(L"SYSTEM"))
      {
        lexer->nextToken();
        stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::SYSTEM)));
      }
      //         break;
      // }else{
      //         break;
    }

    if (stmt->getResourceType() != nullptr &&
        lexer->token()->name->c_str() == Token::COLONCOLON.name->c_str())
    {
      lexer->nextToken(); // sql server
    }

    SQLExpr_ptr expr = nullptr;
    if (lexer->token()->name->c_str() == Token::DOT.name->c_str())
    {
      expr = SQLAllColumnExpr_ptr(new SQLAllColumnExpr());
      lexer->nextToken();
    }
    else
    {
      expr = this->exprParser->expr();
    }

    if (stmt->getResourceType()->name->c_str() == SQLObjectType::TABLE.name->c_str() ||
        stmt->getResourceType() == nullptr)
    {
      stmt->setResource(SQLExprTableSource_ptr(new SQLExprTableSource(expr)));
    }
    else
    {
      stmt->setResource(expr);
    }
  }

  if (lexer->token()->name->c_str() == Token::TO.name->c_str())
  {
    lexer->nextToken();
    for (;;)
    {
      SQLExpr_ptr user = parseUser();
      stmt->getUsers()->push_back(user);
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }

      break;
    }
  }

  if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
  {
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::GRANT.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("OPTION");
      stmt->setWithGrantOption(BOOL::TRUE);
    }

    for (;;)
    {
      if (lexer->identifierEquals(L"MAX_QUERIES_PER_HOUR"))
      {
        lexer->nextToken();
        stmt->setMaxQueriesPerHour(this->exprParser->primary());
        continue;
      }

      if (lexer->identifierEquals(L"MAX_UPDATES_PER_HOUR"))
      {
        lexer->nextToken();
        stmt->setMaxUpdatesPerHour(this->exprParser->primary());
        continue;
      }

      if (lexer->identifierEquals(L"MAX_CONNECTIONS_PER_HOUR"))
      {
        lexer->nextToken();
        stmt->setMaxConnectionsPerHour(this->exprParser->primary());
        continue;
      }

      if (lexer->identifierEquals(L"MAX_USER_CONNECTIONS"))
      {
        lexer->nextToken();
        stmt->setMaxUserConnections(this->exprParser->primary());
        continue;
      }

      break;
    }
  }

  if (lexer->identifierEquals(L"ADMIN"))
  {
    lexer->nextToken();
    acceptIdentifier("OPTION");
    stmt->setAdminOption(BOOL::TRUE);
  }

  if (lexer->identifierEquals(FnvHash::Constants::IDENTIFIED))
  {
    lexer->nextToken();
    accept(Token::BY);

    if (lexer->identifierEquals(L"PASSWORD"))
    {
      lexer->nextToken();
      std::wstring password = *lexer->stringVal();
      accept(Token::LITERAL_CHARS);
      stmt->setIdentifiedByPassword(make_string_ptr(encode_util::UnicodeToUTF8(password)));
    }
    else
    {
      stmt->setIdentifiedBy(this->exprParser->expr());
    }
  }

  if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::GRANT.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("OPTION");
      stmt->setWithGrantOption(BOOL::TRUE);
    }
  }

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseSavePoint()
{

  // 	//LOG_INFO << ", in SQLStatementParser::parseSavePoint, step 1";
  // 	acceptIdentifier("SAVEPOINT");
  // 	SQLSavePointStatement *stmt = new SQLSavePointStatement();
  // 	stmt->setName(this->exprParser->getName());
  // 	return stmt;
}

SQLStatement_ptr SQLStatementParser::parseReleaseSavePoint()
{

  // 	//LOG_INFO << ", in SQLStatementParser::parseReleaseSavePoint, step 1";
  // 	acceptIdentifier("RELEASE");
  // 	acceptIdentifier("SAVEPOINT");
  // 	SQLReleaseSavePointStatement *stmt = new SQLReleaseSavePointStatement();
  // 	stmt->setName(this->exprParser->getName());
  // 	return stmt;
  return NULL;
}

SQLStatement_ptr SQLStatementParser::parseAlter()
{
  // 	//LOG_INFO << ", in SQLStatementParser::parseAlter, step 1";
  // 	accept(ALTER);

  // 	if (lexer->token()->name->c_str() == Token::TABLE) {
  // 		lexer->nextToken();

  // 		SQLAlterTableStatement *stmt = new SQLAlterTableStatement();
  // 		stmt->setName(this->exprParser->getName());

  // 		for (;;) {
  // 			if (lexer->token()->name->c_str() == Token::DROP) {
  // 				parseAlterDrop(stmt);
  // 			} else if (identifierEquals("ADD")) {
  // 				lexer->nextToken();

  // 				if (lexer->token()->name->c_str() == Token::PRIMARY) {
  // 					SQLPrimaryKey *primaryKey = this->exprParser->parsePrimaryKey();
  // 					SQLAlterTableAddConstraint *item = new SQLAlterTableAddConstraint(primaryKey);
  // 					stmt->getItems().push_back(item);
  // 				} else if (lexer->token()->name->c_str() == Token::IDENTIFIER) {
  // 					SQLAlterTableAddColumn *item = parseAlterTableAddColumn();
  // 					stmt->getItems().push_back(item);
  // 				} else {

  // 					std::stringstream stream;
  // 					stream << "TODO " <<  *lexer->token() <<  " "  <<  lexer->stringVal();
  // 					throw new ParserException(stream.str());
  // 					//throw new ParserException("TODO " + *lexer->token() + " " + lexer->stringVal());
  // 				}
  // 			} else if (lexer->token()->name->c_str() == Token::DISABLE) {
  // 				lexer->nextToken();

  // 				if (lexer->token()->name->c_str() == Token::CONSTRAINT) {
  // 					lexer->nextToken();
  // 					SQLAlterTableDisableConstraint *item = new SQLAlterTableDisableConstraint();
  // 					item->setConstraintName(this->exprParser->getName());
  // 					stmt->getItems().push_back(item);
  // 				} else {
  // 					acceptIdentifier("KEYS");
  // 					SQLAlterTableDisableKeys *item = new SQLAlterTableDisableKeys();
  // 					stmt->getItems().push_back(item);
  // 				}
  // 			} else if (lexer->token()->name->c_str() == Token::ENABLE) {
  // 				lexer->nextToken();
  // 				if (lexer->token()->name->c_str() == Token::CONSTRAINT) {
  // 					lexer->nextToken();
  // 					SQLAlterTableEnableConstraint *item = new SQLAlterTableEnableConstraint();
  // 					item->setConstraintName(this->exprParser->getName());
  // 					stmt->getItems().push_back(item);
  // 				} else {
  // 					acceptIdentifier("KEYS");
  // 					SQLAlterTableEnableKeys *item = new SQLAlterTableEnableKeys();
  // 					stmt->getItems().push_back(item);
  // 				}
  // 			} else if (lexer->token()->name->c_str() == Token::ALTER) {
  // 				lexer->nextToken();
  // 				if (lexer->token()->name->c_str() == Token::COLUMN) {
  // 					lexer->nextToken();
  // 					SQLColumnDefinition *column = this->exprParser->parseColumn();
  // 					SQLAlterTableAlterColumn *alterColumn = new SQLAlterTableAlterColumn();
  // 					alterColumn->setColumn(column);
  // 					stmt->getItems().push_back(alterColumn);
  // 				} else {

  // 					std::stringstream stream;
  // 					stream << "TODO " <<  *lexer->token() <<  " "  <<  lexer->stringVal();
  // 					throw new ParserException(stream.str());
  // 					//throw new ParserException("TODO " + *lexer->token() + " " + lexer->stringVal());
  // 				}
  // 			} else if (lexer->token()->name->c_str() == Token::WITH) {
  // 				lexer->nextToken();
  // 				acceptIdentifier("NOCHECK");
  // 				acceptIdentifier("ADD");
  // 				SQLConstraint *check = this->exprParser->parseConstaint();

  // 				SQLAlterTableAddConstraint *addCheck = new SQLAlterTableAddConstraint();
  // 				addCheck->setWithNoCheck(BOOL::TRUE);
  // 				addCheck->setConstraint(check);
  // 				stmt->getItems().push_back(addCheck);
  // 			} else {
  // 				break;
  // 			}
  // 		}

  // 		return stmt;
  return NULL;
}

// 	std::stringstream stream;
// 	stream << "TODO " <<  *lexer->token() <<  " "  <<  lexer->stringVal();
// 	throw new ParserException(stream.str());
// 	//throw new ParserException("TODO " + *lexer->token() + " " + lexer->stringVal());
// }

// void SQLStatementParser::parseAlterDrop(SQLAlterTableStatement *stmt) {
// 	//LOG_INFO << ", in SQLStatementParser::parseAlterDrop, step 1";
// 	lexer->nextToken();

// 	if (lexer->token()->name->c_str() == Token::CONSTRAINT) {
// 		lexer->nextToken();
// 		// SQLAlterTableDropConstraint *item = new SQLAlterTableDropConstraint();
// 		// item->setConstraintName(this->exprParser->getName());
// 		// stmt->getItems().push_back(item);
// 	} else if (lexer->token()->name->c_str() == Token::COLUMN) {
// 		lexer->nextToken();
// 		// SQLAlterTableDropColumnItem *item = new SQLAlterTableDropColumnItem();
// 		// this->exprParser->getNames(item->getColumns());
// 		// stmt->getItems().push_back(item);
// 	} else {

// 		std::stringstream stream;
// 		stream << "TODO " <<  *lexer->token() <<  " "  <<  lexer->stringVal();
// 		throw new ParserException(stream.str());
// 		//throw new ParserException("TODO " + *lexer->token() + " " + lexer->stringVal());
// 	}
// }

SQLStatement_ptr SQLStatementParser::parseRename()
{

  std::stringstream stream;
  stream << "TODO " << lexer->token()->getName()->c_str() << " " << lexer->stringVal()->c_str();
  throw new ParserException(make_string_ptr(stream.str()));
  // throw new ParserException("TODO " + *lexer->token() + " " + lexer->stringVal());
}

SQLDropTableStatement_ptr SQLStatementParser::parseDropTable(BOOL_ptr acceptDrop)
{
  LOG_INFO << "acceptDrop:" << acceptDrop;
  if (acceptDrop)
  {
    accept(Token::DROP);
  }

  SQLDropTableStatement_ptr stmt = SQLDropTableStatement_ptr(new SQLDropTableStatement());

  LOG_INFO << "lexer test:" << lexer->stringVal();
  if (identifierEquals("TEMPORARY"))
  {
    lexer->nextToken();
    stmt->setTemporary(BOOL::TRUE);
  }

  accept(Token::TABLE);

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  for (;;)
  {
    SQLName_ptr name = SQLName_ptr(this->exprParser->getName());
    stmt->getTableSources()->push_back(SQLExprTableSource_ptr(new SQLExprTableSource(name)));
    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    break;
  }

  for (;;)
  {
    if (identifierEquals("RESTRICT"))
    {
      lexer->nextToken();
      stmt->setRestrict(BOOL::TRUE);
      continue;
    }

    if (identifierEquals("CASCADE"))
    {
      lexer->nextToken();
      stmt->setCascade(BOOL::TRUE);

      if (identifierEquals("CONSTRAINTS"))
      { // for oracle
        lexer->nextToken();
      }

      continue;
    }

    if (lexer->token()->name->c_str() == Token::PURGE.name->c_str())
    {
      lexer->nextToken();
      stmt->setPurge(BOOL::TRUE);
      continue;
    }

    break;
  }

  return stmt;
}

// SQLDropSequenceStatement *SQLStatementParser::parseDropSequece(BOOL_ptr acceptDrop) {
// 	//LOG_INFO << ", in SQLStatementParser::parseDropSequece, step 1";
// 	if (acceptDrop) {
// 		accept(DROP);
// 	}

// 	lexer->nextToken();

// 	SQLName_ptr name = this->exprParser->getName();

// 	SQLDropSequenceStatement *stmt = new SQLDropSequenceStatement();
// 	stmt->setName(name);
// 	return stmt;
// }

SQLDropTriggerStatement_ptr SQLStatementParser::parseDropTrigger(BOOL_ptr acceptDrop)
{
  // LOG_INFO << ", in SQLStatementParser::parseDropTrigger, step 1";
  if (acceptDrop)
  {
    accept(Token::DROP);
  }

  lexer->nextToken();

  SQLName_ptr name = this->exprParser->getName();

  SQLDropTriggerStatement_ptr stmt = SQLDropTriggerStatement_ptr(new SQLDropTriggerStatement());
  stmt->setName(name);
  return stmt;
}

SQLDropViewStatement_ptr SQLStatementParser::parseDropView(BOOL_ptr acceptDrop)
{
  // LOG_INFO << ", in SQLStatementParser::parseDropView, step 1";
  if (acceptDrop)
  {
    accept(Token::DROP);
  }

  SQLDropViewStatement_ptr stmt = SQLDropViewStatement_ptr(new SQLDropViewStatement());

  accept(Token::VIEW);

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  for (;;)
  {
    SQLName_ptr name = SQLName_ptr(this->exprParser->getName());
    stmt->getTableSources()->push_back(SQLExprTableSource_ptr(new SQLExprTableSource(name)));
    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    break;
  }

  if (identifierEquals("RESTRICT"))
  {
    lexer->nextToken();
    stmt->setRestrict(BOOL::TRUE);
  }
  else if (identifierEquals("CASCADE"))
  {
    lexer->nextToken();

    if (identifierEquals("CONSTRAINTS"))
    { // for oracle
      lexer->nextToken();
    }

    stmt->setCascade(BOOL::TRUE);
  }

  return stmt;
}

// SQLDropDatabaseStatement *SQLStatementParser::parseDropDatabase(BOOL_ptr acceptDrop) {
// 	//LOG_INFO << ", in SQLStatementParser::parseDropDatabase, step 1";
// 	if (acceptDrop) {
// 		accept(DROP);
// 	}

// 	SQLDropDatabaseStatement *stmt = new SQLDropDatabaseStatement();

// 	accept(DATABASE);

// 	if (lexer->token()->name->c_str() == Token::IF) {
// 		lexer->nextToken();
// 		accept(EXISTS);
// 		stmt->setIfExists(BOOL::TRUE);
// 	}

// 	SQLName_ptr name = this->exprParser->getName();
// 	stmt->setDatabase(name);

// 	return stmt;
// }

SQLDropFunctionStatement_ptr SQLStatementParser::parseDropFunction(BOOL_ptr acceptDrop)
{
  if (acceptDrop)
  {
    accept(Token::DROP);
  }

  SQLDropFunctionStatement_ptr stmt = SQLDropFunctionStatement_ptr(new SQLDropFunctionStatement());

  accept(Token::FUNCTION);

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  SQLName_ptr name = this->exprParser->getName();
  stmt->setName(name);

  return stmt;
}

SQLDropTableSpaceStatement_ptr SQLStatementParser::parseDropTablespace(BOOL_ptr acceptDrop)
{
  if (acceptDrop)
  {
    accept(Token::DROP);
  }

  SQLDropTableSpaceStatement_ptr stmt = SQLDropTableSpaceStatement_ptr(new SQLDropTableSpaceStatement());

  accept(Token::TABLESPACE);

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  SQLName_ptr name = this->exprParser->getName();
  stmt->setName(name);

  return stmt;
}

SQLDropProcedureStatement_ptr SQLStatementParser::parseDropProcedure(BOOL_ptr acceptDrop)
{
  if (acceptDrop)
  {
    accept(Token::DROP);
  }

  SQLDropProcedureStatement_ptr stmt = SQLDropProcedureStatement_ptr(new SQLDropProcedureStatement());

  accept(Token::PROCEDURE);

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  SQLName_ptr name = this->exprParser->getName();
  stmt->setName(name);

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseTruncate()
{
  LOG_INFO;
  accept(Token::TRUNCATE);
  LOG_INFO;
  if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
  {
    lexer->nextToken();
  }
  LOG_INFO;
  SQLTruncateStatement_ptr stmt = SQLTruncateStatement_ptr(new SQLTruncateStatement());

  LOG_INFO;
  if (lexer->token()->name->c_str() == Token::ONLY.name->c_str())
  {
    lexer->nextToken();
    stmt->setOnly(BOOL::TRUE);
  }

  LOG_INFO;
  for (;;)
  {
    LOG_INFO;
    SQLName_ptr name = this->exprParser->getName();
    LOG_INFO;
    stmt->addTableSource(name);
    LOG_INFO << "token name:" << lexer->token()->getName();

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }

    break;
  }

  LOG_INFO;
  for (;;)
  {
    LOG_INFO;
    LOG_INFO << "token name:" << lexer->token()->getName();
    if (lexer->token()->name->c_str() == Token::PURGE.name->c_str())
    {
      lexer->nextToken();

      if (identifierEquals("SNAPSHOT"))
      {
        lexer->nextToken();
        acceptIdentifier("LOG");
        stmt->setPurgeSnapshotLog(BOOL::TRUE);
      }
      else
      {

        std::stringstream stream;
        stream << "TODO " << lexer->token()->getName()->c_str() << " " << lexer->stringVal()->c_str();
        throw new ParserException(make_string_ptr(stream.str()));
        // throw new ParserException("TODO : " + *lexer->token() + " " + lexer->stringVal());
      }
      continue;
    }

    LOG_INFO;
    if (lexer->token()->name->c_str() == Token::RESTART.name->c_str())
    {
      lexer->nextToken();
      accept(Token::IDENTITY);
      stmt->setRestartIdentity(BOOL::TRUE);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::SHARE.name->c_str())
    {
      lexer->nextToken();
      accept(Token::IDENTITY);
      stmt->setRestartIdentity(BOOL::FALSE);
      continue;
    }

    LOG_INFO;
    if (lexer->token()->name->c_str() == Token::CASCADE.name->c_str())
    {
      lexer->nextToken();
      stmt->setCascade(BOOL::TRUE);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::RESTRICT.name->c_str())
    {
      lexer->nextToken();
      stmt->setCascade(BOOL::FALSE);
      continue;
    }

    LOG_INFO;
    break;
  }

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseInsert()
{
  LOG_INFO << "new SQLInsertStatement";
  SQLInsertStatement_ptr insertStatement = SQLInsertStatement_ptr(new SQLInsertStatement());

  if (lexer->token()->name->c_str() == Token::INSERT.name->c_str())
  {
    LOG_INFO << "accept INSERT";
    accept(Token::INSERT);
  }

  LOG_INFO << "goto parseInsert0";
  parseInsert0(insertStatement);
  LOG_INFO << "return";
  return insertStatement;
}

void SQLStatementParser::parseInsert0(SQLInsertInto_ptr insertStatement)
{
  parseInsert0(insertStatement, BOOL::TRUE);
}

void SQLStatementParser::parseInsert0_hinits(SQLInsertInto_ptr insertStatement)
{
}

void SQLStatementParser::parseInsert0(SQLInsertInto_ptr insertStatement, BOOL_ptr acceptSubQuery)
{
  if (lexer->token()->name->c_str() == Token::INTO.name->c_str())
  {
    LOG_INFO << "token name INTO";
    lexer->nextToken();
    LOG_INFO << "token name " << lexer->token()->getName();

    SQLName_ptr tableName = this->exprParser->name();
    insertStatement->setTableName(tableName);

    if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
    {
      insertStatement->setAlias(tableAlias());
    }

    parseInsert0_hinits(insertStatement);

    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      insertStatement->setAlias(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
      lexer->nextToken();
    }
  }

  if (lexer->token()->name->c_str() == (Token::LPAREN.name->c_str()))
  {
    LOG_INFO << "token name LPAREN";
    lexer->nextToken();
    LOG_INFO << "token name " << lexer->token()->getName();
    parseInsertColumns(insertStatement);
    LOG_INFO << "accept";
    accept(Token::RPAREN);
  }

  if (lexer->token()->name->c_str() == Token::VALUES.name->c_str())
  {
    LOG_INFO << "token name VALUES";
    lexer->nextToken();
    LOG_INFO << "token name " << lexer->token()->getName();
    for (;;)
    {
      if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
      {
        LOG_INFO << "token name LPAREN";
        lexer->nextToken();

        SQLInsertStatement_ValuesClause_ptr values = SQLInsertStatement_ValuesClause_ptr(new SQLInsertStatement_ValuesClause());
        this->exprParser->exprList(values->getValues(), values);
        insertStatement->addValueCause(values);
        accept(Token::RPAREN);
      }
      else
      { // oracle
        SQLInsertStatement_ValuesClause_ptr values = SQLInsertStatement_ValuesClause_ptr(new SQLInsertStatement_ValuesClause());
        SQLExpr_ptr value = this->exprParser->getExpr();
        values->addValue(value);
        insertStatement->addValueCause(values);
      }

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        LOG_INFO << "token name COMMA";
        lexer->nextToken();
        continue;
      }
      else
      {
        LOG_INFO << "break";
        break;
      }
    }
  }
  else if (acceptSubQuery &&
           (lexer->token()->name->c_str() == Token::WITH.name->c_str() ||
            lexer->token()->name->c_str() == Token::SELECT.name->c_str() ||
            lexer->token()->name->c_str() == Token::LPAREN.name->c_str()))
  {
    LOG_INFO << "else";
    SQLSelect_ptr select = this->createSQLSelectParser()->select();
    insertStatement->setQuery(select);
  }
  else if (lexer->identifierEquals(FnvHash::Constants::VALUE))
  {
    LOG_INFO << "else throw";
    std::string tmp = "'values' expected, but 'value'. ";
    tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
    throw new ParserException(make_string_ptr(tmp));
  }
}

void SQLStatementParser::parseInsertColumns(SQLInsertInto_ptr insert)
{
  this->exprParser->exprList(insert->getColumns(), std::dynamic_pointer_cast<SQLObject>(insert));
}

BOOL_ptr SQLStatementParser::parseStatementListDialect(SQLStatement_list_ptr theStatementList)
{
  return BOOL::FALSE;
}

SQLDropUserStatement_ptr SQLStatementParser::parseDropUser()
{
  accept(Token::USER);

  SQLDropUserStatement_ptr stmt = SQLDropUserStatement_ptr(new SQLDropUserStatement());
  for (;;)
  {
    SQLExpr_ptr expr = this->exprParser->getExpr();
    stmt->getUsers()->push_back(expr);
    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    break;
  }

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseDropIndex()
{
  accept(Token::INDEX);
  SQLDropIndexStatement_ptr stmt = SQLDropIndexStatement_ptr(new SQLDropIndexStatement());
  stmt->setIndexName(this->exprParser->getName());

  if (lexer->token()->name->c_str() == Token::ON.name->c_str())
  {
    lexer->nextToken();
    stmt->setTableName(this->exprParser->getName());
  }
  return stmt;
}

SQLCallStatement_ptr SQLStatementParser::parseCall()
{

  BOOL_ptr brace = BOOL::FALSE;
  if (lexer->token()->name->c_str() == Token::LBRACE.name->c_str())
  {
    lexer->nextToken();
    brace = BOOL::TRUE;
  }

  SQLCallStatement_ptr stmt = SQLCallStatement_ptr(new SQLCallStatement());

  if (lexer->token()->name->c_str() == Token::QUES.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EQ);
    string_ptr qm = make_string_ptr("?");
    stmt->setOutParameter(SQLVariantRefExpr_ptr(new SQLVariantRefExpr(qm)));
  }

  acceptIdentifier("CALL");

  stmt->setProcedureName(exprParser->getName());

  if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    lexer->nextToken();
    exprParser->exprList(stmt->getParameters());
    accept(Token::RPAREN);
  }

  if (brace)
  {
    accept(Token::RBRACE);
    stmt->setBrace(BOOL::TRUE);
  }

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseSet()
{
  // 	accept(SET);
  // 	SQLSetStatement *stmt = new SQLSetStatement();

  // 	parseAssignItems(stmt->getItems(), stmt);

  // 	return stmt;
  return NULL;
}

void SQLStatementParser::parseAssignItems(SQLAssignItem_list_ptr items, SQLObject_ptr parent)
{
  parseAssignItems(items, parent, BOOL::TRUE);
}

void SQLStatementParser::parseAssignItems(SQLAssignItem_list_ptr items, SQLObject_ptr parent, BOOL_ptr variant)
{
  // LOG_INFO << ", in SQLStatementParser::parseAssignItems, step 1";
  for (;;)
  {
    SQLAssignItem_ptr item = exprParser->parseAssignItem(variant, parent);
    item->setParent(parent);
    items->push_back(item);

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    else
    {
      break;
    }
  }
}

SQLStatement_ptr SQLStatementParser::parseCreate()
{
  wchar_t markChar = lexer->current();
  int markBp = lexer->bp();

  accept(Token::CREATE);

  Token_ptr token = lexer->token();

  if (token == Token_ptr(new Token(&Token::TABLE)) || identifierEquals("GLOBAL"))
  {
    // SQLCreateTableParser *createTableParser = getSQLCreateTableParser();
    // return createTableParser->parseCrateTable(BOOL::FALSE);
  }
  else if (token == Token_ptr(new Token(&Token::INDEX))     //
           || token == Token_ptr(new Token(&Token::UNIQUE)) //
           || identifierEquals("NONCLUSTERED")              // sql server
  )
  {
    return parseCreateIndex(BOOL::FALSE);
  }
  else if (lexer->token()->name->c_str() == Token::SEQUENCE.name->c_str())
  {
    return parseCreateSequence(BOOL::FALSE);
  }
  else if (token == Token_ptr(new Token(&Token::OR)))
  {
    lexer->nextToken();
    accept(Token::REPLACE);
    if (lexer->token() == Token_ptr(new Token(&Token::PROCEDURE)))
    {
      lexer->reset(markBp, markChar, Token_ptr(new Token(&Token::CREATE)));
      return parseCreateProcedure();
    }

    // lexer->reset(mark_bp, mark_ch, CREATE);
    std::stringstream stream;
    stream << "TODO " << lexer->token()->getName()->c_str() << " " << lexer->stringVal()->c_str();
    throw new ParserException(make_string_ptr(stream.str()));
    // throw new ParserException("TODO " + *lexer->token() + " " + lexer->stringVal());
  }
  else if (token == Token_ptr(new Token(&Token::DATABASE)))
  {
    lexer->nextToken();
    if (identifierEquals("LINK"))
    {
      lexer->reset(markBp, markChar, Token_ptr(new Token(&Token::CREATE)));
      return parseCreateDbLink();
    }

    lexer->reset(markBp, markChar, Token_ptr(new Token(&Token::CREATE)));
    return parseCreateDatabase();
  }
  else if (identifierEquals("PUBLIC") || identifierEquals("SHARE"))
  {
    lexer->reset(markBp, markChar, Token_ptr(new Token(&Token::CREATE)));
    return parseCreateDbLink();
  }
  else if (token == Token_ptr(new Token(&Token::VIEW)))
  {
    // return parseCreateView();
  }
  else if (token == Token_ptr(new Token(&Token::TRIGGER)))
  {
    return parseCreateTrigger();
  }

  std::string tmp = "TODO ";
  tmp += lexer->token()->getName()->c_str();
  throw new ParserException(make_string_ptr(tmp));
}

SQLStatement_ptr SQLStatementParser::parseCreateDbLink()
{
  std::string tmp = "TODO ";
  tmp += lexer->token()->getName()->c_str();
  throw new ParserException(make_string_ptr(tmp));
}

SQLStatement_ptr SQLStatementParser::parseCreateTrigger()
{
  // 	accept(TRIGGER);

  // 	SQLCreateTriggerStatement *stmt = new SQLCreateTriggerStatement();
  // 	stmt->setName(this->exprParser->getName());

  // 	if (identifierEquals("BEFORE")) {
  // 		stmt->setTriggerType(SQLCreateTriggerStatement::BEFORE);
  // 		lexer->nextToken();
  // 	} else if (identifierEquals("AFTER")) {
  // 		stmt->setTriggerType(SQLCreateTriggerStatement::AFTER);
  // 		lexer->nextToken();
  // 	} else if (identifierEquals("INSTEAD")) {
  // 		lexer->nextToken();
  // 		accept(OF);
  // 		stmt->setTriggerType(SQLCreateTriggerStatement::INSTEAD_OF);
  // 	}

  // 	for (;;) {
  // 		if (lexer->token()->name->c_str() == Token::TOKEN_INSERT) {
  // 			lexer->nextToken();
  // 			stmt->getTriggerEvents().push_back(SQLCreateTriggerStatement::TRIGGER_INSERT);
  // 			continue;
  // 		}

  // 		if (lexer->token()->name->c_str() == Token::UPDATE) {
  // 			lexer->nextToken();
  // 			stmt->getTriggerEvents().push_back(SQLCreateTriggerStatement::TRIGGER_UPDATE);
  // 			continue;
  // 		}

  // 		if (lexer->token()->name->c_str() == Token::TOKEN_DELETE) {
  // 			lexer->nextToken();
  // 			stmt->getTriggerEvents().push_back(SQLCreateTriggerStatement::TRIGGER_DELETE);
  // 			continue;
  // 		}
  // 		break;
  // 	}

  // 	accept(ON);
  // 	stmt->setOn(this->exprParser->getName());

  // 	if (lexer->token()->name->c_str() == Token::FOR) {
  // 		lexer->nextToken();
  // 		acceptIdentifier("EACH");
  // 		accept(ROW);
  // 		stmt->setForEachRow(BOOL::TRUE);
  // 	}

  // 	SQLStatement_ptr  body = this->parseBlock();
  // 	stmt->setBody(body);
  // 	return stmt;
  return NULL;
}

SQLStatement_ptr SQLStatementParser::parseBlock()
{
  std::string tmp = "TODO ";
  tmp += lexer->token()->getName()->c_str();
  throw new ParserException(make_string_ptr(tmp));
}

SQLStatement_ptr SQLStatementParser::parseCreateDatabase()
{
  // 	if (lexer->token()->name->c_str() == Token::CREATE) {
  // 		lexer->nextToken();
  // 	}

  // 	accept(DATABASE);

  // 	SQLCreateDatabaseStatement *stmt = new SQLCreateDatabaseStatement();
  // 	stmt->setName(this->exprParser->getName());
  // 	return stmt;
  return NULL;
}

SQLStatement_ptr SQLStatementParser::parseCreateProcedure()
{
  std::string tmp = "TODO ";
  tmp += lexer->token()->getName()->c_str();
  throw new ParserException(make_string_ptr(tmp));
}

SQLStatement_ptr SQLStatementParser::parseCreateSequence(BOOL_ptr acceptCreate)
{
  std::string tmp = "TODO ";
  tmp += lexer->token()->getName()->c_str();
  throw new ParserException(make_string_ptr(tmp));
}

SQLStatement_ptr SQLStatementParser::parseCreateIndex(BOOL_ptr acceptCreate)
{
  // 	if (acceptCreate) {
  // 		accept(CREATE);
  // 	}

  // 	SQLCreateIndexStatement *stmt = new SQLCreateIndexStatement();
  // 	if (lexer->token()->name->c_str() == Token::UNIQUE) {
  // 		lexer->nextToken();
  // 		if (identifierEquals("CLUSTERED")) {
  // 			lexer->nextToken();
  // 			string_ptr  x = "UNIQUE CLUSTERED";
  // 			stmt->setType(x);
  // 		} else {
  // 			string_ptr  x = "UNIQUE";
  // 			stmt->setType(x);
  // 		}
  // 	} else if (identifierEquals("FULLTEXT")) {
  // 		string_ptr  x = "FULLTEXT";
  // 		stmt->setType(x);
  // 		lexer->nextToken();
  // 	} else if (identifierEquals("NONCLUSTERED")) {
  // 		string_ptr  x = "NONCLUSTERED";
  // 		stmt->setType(x);
  // 		lexer->nextToken();
  // 	}

  // 	accept(INDEX);

  // 	stmt->setName(this->exprParser->getName());

  // 	accept(ON);

  // 	stmt->setTable(this->exprParser->getName());

  // 	accept(LPAREN);

  // 	for (;;) {
  // 		SQLSelectOrderByItem *item = this->exprParser->parseSelectOrderByItem();
  // 		item->setParent(stmt);
  // 		stmt->getItems().push_back(item);
  // 		if (lexer->token()->name->c_str() == Token::COMMA) {
  // 			lexer->nextToken();
  // 			continue;
  // 		}
  // 		break;
  // 	}
  // 	accept(RPAREN);

  // 	return stmt;
  return NULL;
}

SQLCreateTableParser_ptr SQLStatementParser::getSQLCreateTableParser()
{
  return SQLCreateTableParser_ptr(new SQLCreateTableParser(this->exprParser));
}

SQLStatement_ptr SQLStatementParser::parseSelect()
{
  LOG_INFO << ", in SQLStatementParser::parseSelect, step 1";
  SQLSelectParser_ptr selectParser = createSQLSelectParser();
  LOG_INFO << ", in SQLStatementParser::parseSelect, step 2";
  SQLSelect_ptr select = selectParser->select();
  LOG_INFO << ", in SQLStatementParser::parseSelect, step 3";
  // delete selectParser;
  LOG_INFO << ", in SQLStatementParser::parseSelect, step 4";
  return SQLStatement_ptr(new SQLSelectStatement(select, getDbType()));
  // return nullptr;
}

SQLSelectParser_ptr SQLStatementParser::createSQLSelectParser()
{
  return SQLSelectParser_ptr(new SQLSelectParser(this->exprParser, selectListCache));
}

SQLSelectParser_ptr SQLStatementParser::createSQLSelectParser(SQLExprParser_ptr exprParser)
{
  return SQLSelectParser_ptr(new SQLSelectParser(exprParser));
}

void SQLStatementParser::parseUpdateSet(SQLUpdateStatement_ptr update)
{
  accept(Token::SET);

  for (;;)
  {
    SQLUpdateSetItem_ptr item = SQLUpdateSetItem_ptr(new SQLUpdateSetItem());

    if (lexer->token()->name->c_str() == (Token::LPAREN.name->c_str()))
    {
      lexer->nextToken();
      SQLListExpr_ptr list = SQLListExpr_ptr(new SQLListExpr());
      this->exprParser->exprList(list->getItems());
      accept(Token::RPAREN);
      item->setColumn(list);
    }
    else
    {
      item->setColumn(this->exprParser->primary());
    }
    accept(Token::EQ);
    item->setValue(this->exprParser->getExpr());
    update->getItems()->push_back(item);

    if (*lexer->token() != Token::COMMA)
    {
      break;
    }

    lexer->nextToken();
  }
}

SQLUpdateStatement_ptr SQLStatementParser::createUpdateStatement()
{
  return SQLUpdateStatement_ptr(new SQLUpdateStatement());
}

SQLDeleteStatement_ptr SQLStatementParser::parseDeleteStatement()
{
  SQLDeleteStatement_ptr deleteStatement = SQLDeleteStatement_ptr(new SQLDeleteStatement());

  if (lexer->token()->name->c_str() == Token::DELETE.name->c_str())
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == (Token::FROM.name->c_str()))
    {
      lexer->nextToken();
    }

    if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
    {
      lexer->nextToken();
    }

    SQLName_ptr tableName = exprParser->getName();

    deleteStatement->setTableName(tableName);
  }

  if (lexer->token()->name->c_str() == (Token::WHERE.name->c_str()))
  {
    lexer->nextToken();
    SQLExpr_ptr where = this->exprParser->getExpr();
    deleteStatement->setWhere(where);
  }

  return deleteStatement;
}

// SQLCreateTableStatement *SQLStatementParser::parseCreateTable() {
// 	// SQLCreateTableParser parser = new SQLCreateTableParser(this->lexer);
// 	// return parser.parseCrateTable();
// 	throw new ParserException("TODO");
// }

// SQLCreateViewStatement *SQLStatementParser::parseCreateView() {
// 	SQLCreateViewStatement *createView = new SQLCreateViewStatement();

// 	if (lexer->token()->name->c_str() == Token::CREATE) {
// 		lexer->nextToken();
// 	}

// 	if (lexer->token()->name->c_str() == Token::OR) {
// 		lexer->nextToken();
// 		accept(REPLACE);
// 		createView->setOrReplace(BOOL::TRUE);
// 	}

// 	this->accept(VIEW);

// 	createView->setName(exprParser->getName());

// 	if (lexer->token()->name->c_str() == Token::LPAREN) {
// 		lexer->nextToken();
// 		this->exprParser->exprList(createView->getColumns());
// 		accept(RPAREN);
// 	}

// 	this->accept(AS);

// 	createView->setSubQuery((new SQLSelectParser(this->exprParser))->select());
// 	//createView.setSubQuery(new SQLSelectParser(this->exprParser).select());
// 	return createView;
// }

SQLCommentStatement_ptr SQLStatementParser::parseComment()
{
  accept(Token::COMMENT);
  SQLCommentStatement_ptr stmt = SQLCommentStatement_ptr(new SQLCommentStatement());

  accept(Token::ON);

  if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
  {
    stmt->setType(SQLCommentStatement_Type::TABLE);
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::COLUMN.name->c_str())
  {
    stmt->setType(SQLCommentStatement_Type::COLUMN);
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::INDEX.name->c_str())
  {
    stmt->setType(SQLCommentStatement_Type::INDEX);
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::VIEW.name->c_str())
  {
    stmt->setType(SQLCommentStatement_Type::VIEW);
    lexer->nextToken();
  }

  stmt->setOn(this->exprParser->name());

  accept(Token::IS);
  stmt->setComment(this->exprParser->expr());

  return stmt;
}

SQLAlterTableAddColumn_ptr SQLStatementParser::parseAlterTableAddColumn()
{
  bool odps = DbType::odps.name->c_str() == dbType->name->c_str() ||
              DbType::hive.name->c_str() == dbType->name->c_str();

  BOOL_ptr columns = BOOL::NIL;
  if (odps)
  {
    if (lexer->identifierEquals(L"COLUMNS"))
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
      {
        lexer->nextToken();
        columns = BOOL::TRUE;
      }
    }
    else if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
      columns = BOOL::TRUE;
    }
  }

  SQLAlterTableAddColumn_ptr item = SQLAlterTableAddColumn_ptr(new SQLAlterTableAddColumn());

  for (;;)
  {
    SQLColumnDefinition_ptr columnDef = this->exprParser->parseColumn();
    item->addColumn(columnDef);

    if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
    {
      Lexer_SavePoint_ptr mark = lexer->mark();
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::DEFAULT.name->c_str())
      {
        lexer->nextToken();
        SQLExpr_ptr defaultExpr = this->exprParser->expr();
        columnDef->setDefaultExpr(defaultExpr);
      }
      else
      {
        lexer->reset(mark);
      }
    }

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      if (lexer->identifierEquals(L"ADD"))
      {
        break;
      }
      continue;
    }
    break;
  }

  if (odps && columns)
  {
    accept(Token::RPAREN);
  }

  if (lexer->identifierEquals(FnvHash::Constants::RESTRICT))
  {
    lexer->nextToken();
    item->setRestrict(BOOL::TRUE);
  }
  else if (lexer->token()->name->c_str() == Token::CASCADE.name->c_str() ||
           lexer->identifierEquals(FnvHash::Constants::CASCADE))
  {
    lexer->nextToken();
    item->setCascade(BOOL::TRUE);
  }
  else
  {
    item->setCascade(BOOL::FALSE);
  }

  return item;
}

SQLStatement_ptr SQLStatementParser::parseStatement()
{
  // std::list<SQLStatement_ptr  > *list = new std::list<SQLStatement_ptr  >;

  // this->parseStatementList(*list, 1);
  this->parseStatementList(yaList, 1);

  return yaList->front();
}

SQLExplainStatement_ptr SQLStatementParser::parseExplain()
{
  accept(Token::EXPLAIN);
  if (identifierEquals("PLAN"))
  {
    lexer->nextToken();
  }

  if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
  {
    lexer->nextToken();
  }

  SQLExplainStatement_ptr explain = SQLExplainStatement_ptr(new SQLExplainStatement());
  explain->setStatement(parseStatement());

  return explain;
}

// SQLAlterTableAddIndex *SQLStatementParser::parseAlterTableAddIndex() {
// 	SQLAlterTableAddIndex *item = new SQLAlterTableAddIndex();

// 	if (lexer->token()->name->c_str() == Token::UNIQUE) {
// 		item->setUnique(BOOL::TRUE);
// 		lexer->nextToken();
// 		if (lexer->token()->name->c_str() == Token::INDEX) {
// 			lexer->nextToken();
// 		}
// 	} else {
// 		accept(INDEX);
// 	}

// 	if (lexer->token()->name->c_str() == Token::LPAREN) {
// 		lexer->nextToken();
// 	} else {
// 		item->setName(this->exprParser->getName());
// 		accept(LPAREN);
// 	}

// 	for (;;) {
// 		SQLSelectOrderByItem *column = this->exprParser->parseSelectOrderByItem();
// 		item->getItems().push_back(column);
// 		if (lexer->token()->name->c_str() == Token::COMMA) {
// 			lexer->nextToken();
// 			continue;
// 		}
// 		break;
// 	}
// 	accept(RPAREN);
// 	return item;
// }

SQLStatement_ptr SQLStatementParser::parseWith()
{
  SQLWithSubqueryClause_ptr with = this->parseWithQuery();

  if (lexer->token()->name->c_str() == Token::SELECT.name->c_str() ||
      lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    SQLSelectParser_ptr selectParser = createSQLSelectParser();
    SQLSelect_ptr select = selectParser->select();
    // select->setWithSubQuery(with);
    // return new SQLSelectStatement(select, dbType);
  }
  else if (lexer->token()->name->c_str() == Token::INSERT.name->c_str())
  {
    // SQLInsertStatement *insert = (SQLInsertStatement)this->parseInsert();
    // insert.setWith(with);
    // return insert;
  }
  else if (lexer->token()->name->c_str() == Token::FROM.name->c_str())
  {
    // HiveMultiInsertStatement *insert = (HiveMultiInsertStatement)this->parseInsert();
    // insert->setWith(with);
    // return insert;
  }
  else if (lexer->token()->name->c_str() == Token::UPDATE.name->c_str())
  {
    SQLUpdateStatement_ptr update = (this->parseUpdateStatement());
    update->setWith(with);
    return update;
  }

  std::string tmp = "TODO ";
  tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
  throw new ParserException(make_string_ptr(tmp));
}

SQLWithSubqueryClause_ptr SQLStatementParser::parseWithQuery()
{
  SQLWithSubqueryClause_ptr withQueryClause = SQLWithSubqueryClause_ptr(new SQLWithSubqueryClause());
  if (lexer->hasComment() && lexer->isKeepComments())
  {
    withQueryClause->addBeforeComment(lexer->readAndResetComments());
  }

  accept(Token::WITH);

  if (lexer->token()->name->c_str() == Token::RECURSIVE.name->c_str() ||
      lexer->identifierEquals(L"RECURSIVE"))
  {
    lexer->nextToken();
    withQueryClause->setRecursive(BOOL::TRUE);
  }

  for (;;)
  {
    SQLWithSubqueryClause_Entry_ptr entry = SQLWithSubqueryClause_Entry_ptr(new SQLWithSubqueryClause_Entry());
    entry->setParent(withQueryClause);

    if (lexer->hasComment() && lexer->isKeepComments())
    {
      string_list_ptr tmp = std::make_shared<std::list<string_ptr>>();//ListTran::tran_class<std::wstring, std::string>(lexer->readAndResetComments());
      for (auto it: *lexer->readAndResetComments()) {
        tmp->push_back(make_string_ptr(encode_util::UnicodeToUTF8(*it)));
      }
      entry->addBeforeComment(tmp);
    }

    string_ptr alias = make_string_ptr(encode_util::UnicodeToUTF8(*this->lexer->stringVal()));
    lexer->nextToken();
    entry->setAlias(alias);

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();

      for (;;)
      {
        if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str())
        {
          break;
        }

        SQLName_ptr name = exprParser->name();
        if (dbType->name == DbType::odps.name)
        {
          if (lexer->identifierEquals(FnvHash::Constants::STRING) ||
              lexer->identifierEquals(FnvHash::Constants::INT) ||
              lexer->identifierEquals(FnvHash::Constants::BIGINT))
          {
            lexer->nextToken(); // skip
          }
        }
        name->setParent(entry);
        entry->getColumns()->push_back(name);
        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
        {
          lexer->nextToken();
          continue;
        }
      }

      accept(Token::RPAREN);
    }

    accept(Token::AS);
    accept(Token::LPAREN);

    if (lexer->token()->name->c_str() == Token::VALUES.name->c_str() ||
        lexer->token()->name->c_str() == Token::WITH.name->c_str() ||
        lexer->token()->name->c_str() == Token::SELECT.name->c_str() ||
        lexer->token()->name->c_str() == Token::LPAREN.name->c_str() ||
        lexer->token()->name->c_str() == Token::FROM.name->c_str())
    {
      entry->setSubQuery(this->createSQLSelectParser()->select());
    }
    else if (lexer->token()->name->c_str() == Token::INSERT.name->c_str())
    {
      entry->setReturningStatement(this->parseInsert());
    }
    else if (lexer->token()->name->c_str() == Token::UPDATE.name->c_str())
    {
      entry->setReturningStatement(this->parseUpdateStatement());
    }
    else if (lexer->token()->name->c_str() == Token::DELETE.name->c_str())
    {
      entry->setReturningStatement(this->parseDeleteStatement());
    }

    accept(Token::RPAREN);

    withQueryClause->addEntry(entry);

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }

    break;
  }

  return withQueryClause;
}

SQLStatement_ptr SQLStatementParser::parseCreateExternalCatalog()
{
  // MySqlCreateExternalCatalogStatement stmt = new MySqlCreateExternalCatalogStatement();

  // if (lexer->token == Token::CREATE) {
  //     lexer->nextToken();
  // }

  // acceptIdentifier("EXTERNAL");
  // acceptIdentifier("CATALOG");

  // if (lexer->token == Token::IF) {
  //     lexer->nextToken();
  //     accept(Token::NOT);
  //     accept(Token::EXISTS);
  //     stmt->setIfNotExists(BOOL::TRUE);
  // }

  // SQLName name = this->exprParser.name();
  // stmt->setName(name);

  // acceptIdentifier("PROPERTIES");
  // accept(Token::LPAREN);

  // for (; ; ) {
  //     SQLName key = this->exprParser.name();
  //     accept(Token::EQ);
  //     SQLName value = this->exprParser.name();

  //     stmt->getProperties().put(key, value);

  //     if (lexer->token == Token::RPAREN) {
  //         accept(Token::RPAREN);
  //         break;
  //     }
  // }

  // if (lexer->token() == Token::COMMENT) {
  //     lexer->nextToken();
  //     SQLName comment = this->exprParser.name();
  //     stmt->setComment(comment);
  // }

  // return stmt;
  return NULL;
}
SQLStatement_ptr SQLStatementParser::parseCreateTableGroup()
{
  accept(Token::ALL);
  acceptIdentifier("TABLEGROUP");

  // SQLCreateTableGroupStatement *stmt = new SQLCreateTableGroupStatement();

  if (lexer->identifierEquals(FnvHash::Constants::IF))
  {
    lexer->nextToken();
    accept(Token::NOT);
    accept(Token::EXISTS);
    // stmt->setIfNotExists(BOOL::TRUE);
  }

  SQLName_ptr name = this->exprParser->name();
  // stmt->setName(name);

  if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str() ||
      lexer->identifierEquals(L"PARTITION"))
  {
    lexer->nextToken();
    acceptIdentifier("NUM");
    SQLExpr_ptr num = this->exprParser->getExpr();
    // stmt->setPartitionNum(num);
  }

  // return stmt;
  return NULL;
}

SQLStatement_ptr SQLStatementParser::parseCreateResourceGroup()
{
  accept(Token::CREATE);
  acceptIdentifier("RESOURCE");
  accept(Token::GROUP);

  // SQLCreateResourceGroupStatement* stmt = new SQLCreateResourceGroupStatement();
  // stmt->setName(this->exprParser->name());

  for (;;)
  {
    if (lexer->token()->name->c_str() == Token::SEMI.name->c_str() ||
        lexer->token()->name->c_str() == Token::XEOF.name->c_str())
    {
      break;
    }
    if (lexer->token()->name->c_str() == Token::ENABLE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setEnable(BOOL::TRUE);
    }
    else if (lexer->token()->name->c_str() == Token::DISABLE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setEnable(BOOL::FALSE);
    }

    Lexer_SavePoint_ptr m = lexer->mark();
    string_ptr name = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr value = this->exprParser->getExpr();
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        SQLListExpr *list_ = new SQLListExpr();
        list_->addItem(value);
        while (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
        {
          lexer->nextToken();
          list_->addItem(this->exprParser->getExpr());
        }
        // stmt->addProperty(name, list_);
      }
      else
      {
        // stmt->addProperty(name, value);
      }
    }
    else
    {
      lexer->reset(m);
      break;
    }
  }

  // return stmt;
  return NULL;
}

SQLStatement_ptr SQLStatementParser::parseCreateMaterializedView()
{
  accept(Token::CREATE);
  acceptIdentifier("MATERIALIZED");
  accept(Token::VIEW);

  // SQLCreateMaterializedViewStatement* stmt = new SQLCreateMaterializedViewStatement();

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::NOT);
    accept(Token::EXISTS);
    // stmt->setIfNotExists(BOOL::TRUE);
  }

  // stmt->setName(this->exprParser->name());

  if (this->dbType->name->c_str() == DbType::mysql.name->c_str())
  {
    // stmt->setDbType(DbType::mysql);

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
      for (;;)
      {
        Token_ptr token = lexer->token();

        if (lexer->identifierEquals(FnvHash::Constants::CLUSTERED))
        {
          lexer->nextToken();
          if (lexer->token()->name->c_str() == Token::KEY.name->c_str())
          {
            // MySqlKey* clsKey = new MySqlKey();
            // this->exprParser.parseIndex(clsKey.getIndexDefinition());
            // clsKey.setIndexType("CLUSTERED");
            // clsKey.setParent(stmt);
            // stmt->getTableElementList().add(clsKey);

            if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
            {
              lexer->nextToken();
              continue;
            }
          }
          else if (lexer->token()->name->c_str() == Token::INDEX.name->c_str())
          {
            // MySqlTableIndex* idx = new MySqlTableIndex();
            // this->exprParser.parseIndex(idx.getIndexDefinition());
            // idx.setIndexType("CLUSTERED");
            // idx.setParent(stmt);
            // stmt->getTableElementList().add(idx);

            if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str())
            {
              break;
            }
            else if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
            {
              lexer->nextToken();
              continue;
            }
          }
        }

        if (*token == Token::IDENTIFIER)
        {
          // SQLColumnDefinition* column = this->exprParser->parseColumn(stmt);
          // stmt->getTableElementList().add((SQLTableElement) column);
        }
        else if (*token == Token::PRIMARY   //
                 || *token == Token::UNIQUE //
                 || *token == Token::CHECK  //
                 || *token == Token::CONSTRAINT || *token == Token::FOREIGN)
        {
          SQLConstraint_ptr constraint = this->exprParser->parseConstaint();
          // constraint->setParent(stmt);
          // stmt->getTableElementList().add((SQLTableElement) constraint);
        }
        else if (lexer->token()->name->c_str() == (Token::INDEX.name->c_str()))
        {
          // MySqlTableIndex* idx = new MySqlTableIndex();
          // this->exprParser.parseIndex(idx.getIndexDefinition());

          // idx.setParent(stmt);
          // stmt->getTableElementList().add(idx);
        }
        else if (lexer->token()->name->c_str() == (Token::KEY.name->c_str()))
        {
          Lexer_SavePoint_ptr savePoint = lexer->mark();
          lexer->nextToken();

          BOOL_ptr isColumn = BOOL::FALSE;
          if (lexer->identifierEquals(FnvHash::Constants::VARCHAR))
          {
            isColumn = BOOL::TRUE;
          }
          lexer->reset(savePoint);

          if (isColumn)
          {
            // stmt->getTableElementList().add(this->exprParser.parseColumn());
          }
          else
          {
            SQLName_ptr name;
            if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
            {
              name = this->exprParser->name();
            }

            // MySqlKey* key = new MySqlKey();
            // this->exprParser.parseIndex(key.getIndexDefinition());

            if (name != NULL)
            {
              // key.setName(name);
            }
            // key.setParent(stmt);
            // stmt->getTableElementList().add(key);
          }
          continue;
        }
        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
        {
          lexer->nextToken();
          continue;
        }
        break;
      }
      accept(Token::RPAREN);
    }

    for (;;)
    {
      if (lexer->identifierEquals(FnvHash::Constants::DISTRIBUTED))
      {
        lexer->nextToken();
        accept(Token::BY);
        if (lexer->identifierEquals(FnvHash::Constants::HASH))
        {
          lexer->nextToken();
          accept(Token::LPAREN);
          for (;;)
          {
            SQLName_ptr name = this->exprParser->name();
            // stmt->getDistributedBy().add(name);
            if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
            {
              lexer->nextToken();
              continue;
            }
            break;
          }
          accept(Token::RPAREN);
          // stmt->setDistributedByType(new SQLIdentifierExpr("HASH"));
        }
        else if (lexer->identifierEquals(FnvHash::Constants::DUPLICATE))
        {
          lexer->nextToken();
          accept(Token::LPAREN);
          for (;;)
          {
            SQLName_ptr name = this->exprParser->name();
            // stmt->getDistributedBy().add(name);
            if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
            {
              lexer->nextToken();
              continue;
            }
            break;
          }
          accept(Token::RPAREN);
          // stmt->setDistributedByType(new SQLIdentifierExpr("DUPLICATE"));
        }
        else if (lexer->identifierEquals(FnvHash::Constants::BROADCAST))
        {
          lexer->nextToken();
          // stmt->setDistributedByType(new SQLIdentifierExpr("BROADCAST"));
        }
        continue;
      }
      else if (lexer->identifierEquals(L"INDEX_ALL"))
      {
        lexer->nextToken();
        accept(Token::EQ);
        if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
        {
          if (StringUtils::equalsIgnoreCase(L"Y", *lexer->stringVal()))
          {
            lexer->nextToken();
            // stmt->addOption("INDEX_ALL", new SQLCharExpr("Y"));
          }
          else if (StringUtils::equalsIgnoreCase(L"N", *lexer->stringVal()))
          {
            lexer->nextToken();
            // stmt->addOption("INDEX_ALL", new SQLCharExpr("N"));
          }
          else
          {
            throw new ParserException(make_string_ptr("INDEX_ALL accept parameter ['Y' or 'N'] only."));
          }
        }
        continue;
      }
      else if (lexer->identifierEquals(FnvHash::Constants::ENGINE))
      {
        lexer->nextToken();
        if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
        {
          lexer->nextToken();
        }
        SQLExpr_ptr expr = this->exprParser->getExpr();
        // stmt->addOption("ENGINE", expr);
        continue;
      }
      else if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str())
      {
        // SQLPartitionBy* partitionBy = this->exprParser.parsePartitionBy();
        // stmt->setPartitionBy(partitionBy);
        continue;
      }
      else if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
      {
        lexer->nextToken();
        if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
        {
          lexer->nextToken();
        }
        // stmt->setComment(this->exprParser->expr());
        continue;
      }
      break;
    }
  }
  else if (dbType->name->c_str() == DbType::odps.name->c_str())
  {
    if (lexer->identifierEquals(FnvHash::Constants::LIFECYCLE))
    {
      lexer->nextToken();
      // stmt->setLifyCycle(this->exprParser->primary());
    }

    if (lexer->token()->name->c_str() == Token::PARTITIONED.name->c_str())
    {
      lexer->nextToken();
      accept(Token::ON);
      accept(Token::LPAREN);
      // this->exprParser.names(stmt->getPartitionedOn(), stmt);
      accept(Token::RPAREN);
    }
  }
  else
  {
    if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str())
    {
      // SQLPartitionBy* partitionBy = this->exprParser.parsePartitionBy();
      // stmt->setPartitionBy(partitionBy);
    }
  }

  for (;;)
  {
    // if (exprParser instanceof OracleExprParser) {
    //     ((OracleExprParser) exprParser).parseSegmentAttributes(stmt);
    // }

    if (lexer->identifierEquals(L"REFRESH"))
    {
      lexer->nextToken();
      BOOL_ptr refresh = BOOL::FALSE;
      for (;;)
      {
        if (lexer->identifierEquals(L"FAST"))
        {
          lexer->nextToken();
          // stmt->setRefreshFast(BOOL::TRUE);

          refresh = BOOL::TRUE;
        }
        else if (lexer->identifierEquals(L"COMPLETE"))
        {
          lexer->nextToken();
          // stmt->setRefreshComplete(BOOL::TRUE);

          refresh = BOOL::TRUE;
        }
        else if (lexer->identifierEquals(FnvHash::Constants::FORCE))
        {
          lexer->nextToken();
          // stmt->setRefreshForce(BOOL::TRUE);

          refresh = BOOL::TRUE;
        }
        else if (lexer->token()->name->c_str() == Token::ON.name->c_str())
        {
          lexer->nextToken();
          if (lexer->token()->name->c_str() == Token::COMMIT.name->c_str() ||
              lexer->identifierEquals(FnvHash::Constants::COMMIT))
          {
            lexer->nextToken();
            // stmt->setRefreshOnCommit(BOOL::TRUE);
            refresh = BOOL::TRUE;
          }
          else if (lexer->identifierEquals(FnvHash::Constants::OVERWRITE))
          {
            lexer->nextToken();
            // stmt->setRefreshOnOverWrite(BOOL::TRUE);

            refresh = BOOL::TRUE;
          }
          else
          {
            acceptIdentifier("DEMAND");
            // stmt->setRefreshOnDemand(BOOL::TRUE);

            refresh = BOOL::TRUE;
          }
        }
        else if (lexer->identifierEquals(FnvHash::Constants::START))
        {
          lexer->nextToken();
          accept(Token::WITH);
          SQLExpr_ptr startWith = this->exprParser->getExpr();
          // stmt->setStartWith(startWith);
          // stmt->setRefreshStartWith(BOOL::TRUE);

          refresh = BOOL::TRUE;
        }
        else if (lexer->identifierEquals(FnvHash::Constants::NEXT))
        {
          lexer->nextToken();
          SQLExpr_ptr next = this->exprParser->getExpr();
          // stmt->setNext(next);
          // stmt->setRefreshNext(BOOL::TRUE);

          refresh = BOOL::TRUE;
        }
        else
        {
          break;
        }
      }

      if (!refresh)
      {
        std::string tmp = "refresh clause is empty. ";
        tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
        throw new ParserException(make_string_ptr(tmp));
      }
    }
    else if (lexer->identifierEquals(L"BUILD"))
    {
      lexer->nextToken();

      if (lexer->identifierEquals(L"IMMEDIATE") ||
          lexer->token()->name->c_str() == Token::IMMEDIATE.name->c_str())
      {
        lexer->nextToken();
        // stmt->setBuildImmediate(BOOL::TRUE);
      }
      else
      {
        accept(Token::DEFERRED);
        // stmt->setBuildDeferred(BOOL::TRUE);
      }
    }
    else if (lexer->identifierEquals(L"PARALLEL"))
    {
      lexer->nextToken();
      // stmt->setParallel(BOOL::TRUE);
      if (lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str())
      {
        // stmt->setParallelValue(lexer->integerValue());
        lexer->nextToken();
      }
    }
    else if (lexer->identifierEquals(FnvHash::Constants::NOCACHE) || lexer->token()->name->c_str() == Token::NOCACHE.name->c_str())
    {
      lexer->nextToken();
      // stmt->setCache(BOOL::FALSE);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::NOPARALLEL))
    {
      lexer->nextToken();
      // stmt->setParallel(BOOL::FALSE);
    }
    else if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("ROWID");
      // stmt->setWithRowId(BOOL::TRUE);
    }
    else
    {
      break;
    }
  }

  BOOL_ptr enableQueryRewrite;
  if (lexer->token()->name->c_str() == Token::ENABLE.name->c_str())
  {
    lexer->nextToken();
    enableQueryRewrite = BOOL::TRUE;
  }

  else if (lexer->token()->name->c_str() == Token::DISABLE.name->c_str())
  {
    lexer->nextToken();
    enableQueryRewrite = BOOL::FALSE;
  }

  // if (enableQueryRewrite != NULL) {
  else
  {
    acceptIdentifier("QUERY");
    acceptIdentifier("REWRITE");
    // stmt->setEnableQueryRewrite(enableQueryRewrite);
  }

  accept(Token::AS);
  SQLSelect_ptr select = this->createSQLSelectParser()->select();
  // stmt->setQuery(select);

  // return stmt;
  return NULL;
}

SQLStatement_ptr SQLStatementParser::parseCreateRole()
{
  accept(Token::CREATE);
  acceptIdentifier("ROLE");
  SQLName_ptr name = this->exprParser->name();

  // SQLCreateRoleStatement* stmt = new SQLCreateRoleStatement(dbType);
  // stmt->setName(name);

  // return stmt;
  return NULL;
}

SQLStatement_ptr SQLStatementParser::parseShowMaterializedView()
{
  if (lexer->token()->name->c_str() == Token::SHOW.name->c_str())
  {
    lexer->nextToken();
  }
  // SQLShowMaterializedViewStatement* stmt = new SQLShowMaterializedViewStatement();
  // stmt->setDbType(dbType);

  acceptIdentifier("MATERIALIZED");

  acceptIdentifier("VIEWS");

  if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
  {
    lexer->nextToken();
    // stmt->setLike(this->exprParser->charExpr());
  }

  // return stmt;
  return NULL;
}

SQLUpdateStatement_ptr SQLStatementParser::parseUpdateStatement()
{
  SQLUpdateStatement_ptr udpateStatement = createUpdateStatement();

  if (lexer->token()->name->c_str() == Token::UPDATE.name->c_str())
  {
    lexer->nextToken();

    SQLTableSource_ptr tableSource = this->exprParser->createSelectParser()->parseTableSource();
    udpateStatement->setTableSource(tableSource);
  }

  if (dbType->name->c_str() == DbType::odps.name->c_str() &&
      lexer->token()->name->c_str() == Token::PARTITION.name->c_str())
  {
    lexer->nextToken();
    SQLAssignItem_list_ptr partitions = std::make_shared<std::list<SQLAssignItem_ptr>>();
    udpateStatement->setPartitions(partitions);
    this->exprParser->parseAssignItem(udpateStatement->getPartitions(), std::dynamic_pointer_cast<SQLObject>((udpateStatement)));
  }

  parseUpdateSet(udpateStatement);

  if (lexer->token()->name->c_str() == (Token::WHERE.name->c_str()))
  {
    lexer->nextToken();
    udpateStatement->setWhere(this->exprParser->getExpr());
  }

  return udpateStatement;
}

SQLStatement_ptr SQLStatementParser::parseDrop()
{
  string_list_ptr beforeComments = std::make_shared<std::list<string_ptr>>();
  if (lexer->isKeepComments() && lexer->hasComment())
  {
    // beforeComments = lexer->readAndResetComments();
    beforeComments->clear();
    for (auto it : *lexer->readAndResetComments())
    {
      beforeComments->push_back(make_string_ptr(encode_util::UnicodeToUTF8(*it)));
    }
  }

  Lexer_SavePoint_ptr mark = lexer->mark();
  lexer->nextToken();
  LOG_INFO << "token name:" << lexer->token()->getName()->c_str();

  SQLStatement_ptr stmt;

  SQLCommentHint_list_ptr hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
  if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
  {
    hints = this->exprParser->parseHints();
  }

  BOOL_ptr temporary = BOOL::FALSE;

  if (lexer->token()->name->c_str() == Token::TEMPORARY.name->c_str() ||
      lexer->identifierEquals(FnvHash::Constants::TEMPORARY))
  {
    lexer->nextToken();
    temporary = BOOL::TRUE;
  }

  BOOL_ptr physical = BOOL::FALSE;
  if (lexer->identifierEquals(FnvHash::Constants::PHYSICAL))
  {
    lexer->nextToken();
    physical = BOOL::TRUE;
  }

  if (lexer->token()->name->c_str() == Token::USER.name->c_str())
  {
    stmt = (parseDropUser());
  }
  if (lexer->token()->name->c_str() == Token::INDEX.name->c_str())
  {
    stmt = parseDropIndex();
  }
  if (lexer->token()->name->c_str() == Token::VIEW.name->c_str())
  {
    stmt = (parseDropView(BOOL::FALSE));
  }
  if (lexer->token()->name->c_str() == Token::TRIGGER.name->c_str())
  {
    stmt = (parseDropTrigger(BOOL::FALSE));
  }
  if (lexer->token()->name->c_str() == Token::DATABASE.name->c_str())
  {
    stmt = (parseDropDatabaseOrSchema(BOOL::FALSE));
    if (physical)
    {
      (std::dynamic_pointer_cast<SQLDropDatabaseStatement>(stmt))->setPhysical(physical);
    }
  }
  if (lexer->token()->name->c_str() == Token::SCHEMA.name->c_str())
  {
    if (dbType == DbType_ptr(new DbType(&DbType::postgresql)))
    {
      stmt = (parseDropSchema());
    }
    else
    {
      stmt = (parseDropDatabaseOrSchema(BOOL::FALSE));
      if (physical)
      {
        (std::dynamic_pointer_cast<SQLDropDatabaseStatement>(stmt))->setPhysical(physical);
      }
    }
  }
  if (lexer->token()->name->c_str() == Token::FUNCTION.name->c_str())
  {
    SQLDropFunctionStatement_ptr dropFunc = (parseDropFunction(BOOL::FALSE));
    if (temporary)
    {
      dropFunc->setTemporary(BOOL::TRUE);
    }
    stmt = dropFunc;
  }
  if (lexer->token()->name->c_str() == Token::TABLESPACE.name->c_str())
  {
    stmt = (parseDropTablespace(BOOL::FALSE));
  }
  if (lexer->token()->name->c_str() == Token::PROCEDURE.name->c_str())
  {
    stmt = (parseDropProcedure(BOOL::FALSE));
  }
  if (lexer->token()->name->c_str() == Token::SEQUENCE.name->c_str())
  {
    stmt = (parseDropSequence(BOOL::FALSE));
  }
  if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
  {
    SQLDropTableStatement_ptr dropTable = (parseDropTable(BOOL::FALSE));
    if (temporary)
    {
      dropTable->setTemporary(BOOL::TRUE);
    }
    if (!hints->empty())
    {
      dropTable->setHints(hints);
    }
    stmt = dropTable;
  }
  else
  {
    if (lexer->token()->name->c_str() == Token::TABLE.name->c_str() ||
        lexer->identifierEquals(L"TEMPORARY") ||
        lexer->identifierEquals(FnvHash::Constants::PARTITIONED))
    {
      SQLDropTableStatement_ptr dropTable = (parseDropTable(BOOL::FALSE));
      LOG_INFO << "hints.size():" << hints->size();
      if (!hints->empty())
      {
        dropTable->setHints(hints);
      }
      stmt = dropTable;
    }
    else if (lexer->identifierEquals(FnvHash::Constants::TABLES))
    {
      stmt = (parseDropTable(BOOL::FALSE));
    }
    else if (lexer->identifierEquals(FnvHash::Constants::EVENT))
    {
      stmt = parseDropEvent();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::RESOURCE))
    {
      stmt = parseDropResource();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::LOGFILE))
    {
      stmt = parseDropLogFileGroup();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::SERVER))
    {
      stmt = parseDropServer();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::TABLEGROUP))
    {
      stmt = parseDropTableGroup();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::ROLE))
    {
      lexer->reset(mark);
      stmt = parseDropRole();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::OUTLINE))
    {
      lexer->reset(mark);
      stmt = parseDropOutline();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::EXTERNAL))
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
      {
        lexer->reset(mark);
        stmt = (parseDropTable(BOOL::TRUE));
      }
      else if (lexer->identifierEquals(FnvHash::Constants::CATALOG))
      {
        lexer->reset(mark);
        stmt = parseDropCatalog();
      }
      else
      {
        std::string tmp = "TODO ";
        tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
        throw new ParserException(make_string_ptr(tmp));
      }
    }
    else if (lexer->token()->name->c_str() == Token::FULLTEXT.name->c_str())
    {
      lexer->nextToken();

      FullTextType_ptr type = parseFullTextType();
      SQLName_ptr name = this->exprParser->name();

      MysqlDropFullTextStatement_ptr x = MysqlDropFullTextStatement_ptr(new MysqlDropFullTextStatement());
      x->setName(name);
      x->setType(type);
      stmt = x;
    }
    else if (lexer->identifierEquals(L"INSTANCE_GROUP"))
    {
      lexer->nextToken();
      MySqlManageInstanceGroupStatement_ptr x = MySqlManageInstanceGroupStatement_ptr(new MySqlManageInstanceGroupStatement());
      string_ptr tmp = make_string_ptr("DROP");
      x->setOperation(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp)));

      for (;;)
      {
        x->getGroupNames()->push_back(exprParser->expr());
        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
        {
          lexer->nextToken();
          continue;
        }
        break;
      }
      stmt = x;
    }
    else if (lexer->identifierEquals(L"MATERIALIZED"))
    {
      stmt = parseDropMaterializedView();
    }
    else if (lexer->identifierEquals(L"OFFLINEMODEL"))
    {
      stmt = parseDropOfflineModel();
    }
    else
    {
      std::string tmp = "TODO ";
      tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
      throw new ParserException(make_string_ptr(tmp));
    }
  }

  if (!beforeComments->empty())
  {
    stmt->addBeforeComment(beforeComments);
  }

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseDropOfflineModel()
{
  if (lexer->token()->name->c_str() == Token::DROP.name->c_str())
  {
    lexer->nextToken();
  }
  SQLDropOfflineModelStatement_ptr stmt = SQLDropOfflineModelStatement_ptr(new SQLDropOfflineModelStatement());
  stmt->setDbType(dbType);

  acceptIdentifier("OFFLINEMODEL");

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  stmt->setName(this->exprParser->name());
  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseDropMaterializedView()
{
  if (lexer->token()->name->c_str() == Token::DROP.name->c_str())
  {
    lexer->nextToken();
  }
  SQLDropMaterializedViewStatement_ptr stmt = SQLDropMaterializedViewStatement_ptr(new SQLDropMaterializedViewStatement());
  stmt->setDbType(dbType);

  acceptIdentifier("MATERIALIZED");

  accept(Token::VIEW);

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  stmt->setName(this->exprParser->name());
  return stmt;
}

FullTextType_ptr SQLStatementParser::parseFullTextType()
{
  FullTextType_ptr textType;

  if (lexer->identifierEquals(FnvHash::Constants::CHARFILTER))
  {
    textType = FullTextType::CHARFILTER;
  }
  else if (lexer->identifierEquals(FnvHash::Constants::TOKENIZER))
  {
    textType = FullTextType::TOKENIZER;
  }
  else if (lexer->identifierEquals(FnvHash::Constants::TOKENFILTER))
  {
    textType = FullTextType::TOKENFILTER;
  }
  else if (lexer->identifierEquals(FnvHash::Constants::ANALYZER))
  {
    textType = FullTextType::ANALYZER;
  }
  else if (lexer->identifierEquals(FnvHash::Constants::DICTIONARY))
  {
    textType = FullTextType::DICTIONARY;
  }
  else
  {
    throw new ParserException(make_string_ptr("type of full text must be [CHARFILTER/TOKENIZER/TOKENFILTER/ANALYZER/DICTIONARY] ."));
  }
  lexer->nextToken();
  return textType;
}

SQLStatement_ptr SQLStatementParser::parseDropCatalog()
{
  accept(Token::DROP);

  SQLDropCatalogStatement_ptr stmt = SQLDropCatalogStatement_ptr(new SQLDropCatalogStatement(dbType));

  if (lexer->identifierEquals(FnvHash::Constants::EXTERNAL))
  {
    stmt->setExternal(BOOL::TRUE);
    lexer->nextToken();
  }

  acceptIdentifier("CATALOG");
  SQLName_ptr name = this->exprParser->name();
  stmt->setName(name);

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseDropOutline()
{
  accept(Token::DROP);

  SQLDropOutlineStatement_ptr stmt = SQLDropOutlineStatement_ptr(new SQLDropOutlineStatement());
  stmt->setDbType(dbType);

  acceptIdentifier("OUTLINE");
  SQLName_ptr name = this->exprParser->name();
  stmt->setName(name);

  return stmt;
}

SQLDropStatement_ptr  SQLStatementParser::parseDropDatabaseOrSchema(BOOL_ptr acceptDrop)
{
  if (acceptDrop)
  {
    accept(Token::DROP);
  }

  SQLDropDatabaseStatement_ptr stmt = SQLDropDatabaseStatement_ptr(new SQLDropDatabaseStatement(getDbType()));

  if (lexer->token()->name->c_str() == Token::SCHEMA.name->c_str())
  {
    lexer->nextToken();
  }
  else
  {
    accept(Token::DATABASE);
  }

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  SQLName_ptr name = SQLName_ptr(this->exprParser->name());
  stmt->setDatabase(name);

  if (lexer->identifierEquals(FnvHash::Constants::RESTRICT))
  {
    lexer->nextToken();
    stmt->setRestrict(BOOL::TRUE);
  }
  else if (lexer->token()->name->c_str() == Token::CASCADE.name->c_str() || lexer->identifierEquals(FnvHash::Constants::CASCADE))
  {
    lexer->nextToken();
    stmt->setCascade(BOOL::TRUE);
  }
  else
  {
    stmt->setCascade(BOOL::FALSE);
  }

  return stmt;
}

SQLDropStatement_ptr SQLStatementParser::parseDropSchema()
{
  std::string tmp = "TODO ";
  tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
  throw new ParserException(make_string_ptr(tmp));
}

SQLDropSequenceStatement_ptr SQLStatementParser::parseDropSequence(BOOL_ptr acceptDrop)
{
  if (acceptDrop)
  {
    accept(Token::DROP);
  }

  lexer->nextToken();

  SQLName_ptr name = this->exprParser->name();

  SQLDropSequenceStatement_ptr stmt = SQLDropSequenceStatement_ptr(new SQLDropSequenceStatement(getDbType()));
  stmt->setName(name);
  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseDropEvent()
{
  if (lexer->token()->name->c_str() == Token::DROP.name->c_str())
  {
    lexer->nextToken();
  }

  acceptIdentifier("EVENT");

  SQLDropEventStatement_ptr stmt = SQLDropEventStatement_ptr(new SQLDropEventStatement());
  stmt->setDbType(dbType);

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  SQLName_ptr name = this->exprParser->name();
  stmt->setName(name);

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseDropResource()
{
  if (lexer->token()->name->c_str() == Token::DROP.name->c_str())
  {
    lexer->nextToken();
  }

  acceptIdentifier("RESOURCE");

  if (lexer->token()->name->c_str() == Token::GROUP.name->c_str())
  {
    lexer->nextToken();
    SQLDropResourceGroupStatement_ptr stmt = SQLDropResourceGroupStatement_ptr(new SQLDropResourceGroupStatement());
    stmt->setDbType(dbType);

    if (lexer->token()->name->c_str() == Token::IF.name->c_str())
    {
      lexer->nextToken();
      accept(Token::EXISTS);
      stmt->setIfExists(BOOL::TRUE);
    }

    SQLName_ptr name = this->exprParser->name();
    stmt->setName(name);

    return stmt;
  }

  SQLDropResourceStatement_ptr stmt = SQLDropResourceStatement_ptr(new SQLDropResourceStatement());
  stmt->setDbType(dbType);

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  SQLName_ptr name = this->exprParser->name();
  stmt->setName(name);

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseDropLogFileGroup()
{
  if (lexer->token()->name->c_str() == Token::DROP.name->c_str())
  {
    lexer->nextToken();
  }

  acceptIdentifier("LOGFILE");
  accept(Token::GROUP);

  SQLDropLogFileGroupStatement_ptr stmt = SQLDropLogFileGroupStatement_ptr(new SQLDropLogFileGroupStatement());
  stmt->setDbType(dbType);

  SQLName_ptr name = this->exprParser->name();
  stmt->setName(name);

  if (lexer->identifierEquals(FnvHash::Constants::ENGINE))
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      lexer->nextToken();
    }
    SQLExpr_ptr engine = this->exprParser->primary();
    stmt->setEngine(engine);
  }

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseDropServer()
{
  if (lexer->token()->name->c_str() == Token::DROP.name->c_str())
  {
    lexer->nextToken();
  }

  acceptIdentifier("SERVER");

  SQLDropServerStatement_ptr stmt = SQLDropServerStatement_ptr(new SQLDropServerStatement());
  stmt->setDbType(dbType);

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  SQLName_ptr name = this->exprParser->name();
  stmt->setName(name);

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseDropTableGroup()
{
  if (lexer->token()->name->c_str() == Token::DROP.name->c_str())
  {
    lexer->nextToken();
  }

  acceptIdentifier("TABLEGROUP");

  SQLDropTableGroupStatement_ptr stmt = SQLDropTableGroupStatement_ptr(new SQLDropTableGroupStatement());
  stmt->setDbType(dbType);

  if (lexer->token()->name->c_str() == Token::IF.name->c_str())
  {
    lexer->nextToken();
    accept(Token::EXISTS);
    stmt->setIfExists(BOOL::TRUE);
  }

  SQLName_ptr name = this->exprParser->name();
  stmt->setName(name);

  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseDropRole()
{
  accept(Token::DROP);
  acceptIdentifier("ROLE");

  SQLDropRoleStatement_ptr stmt = SQLDropRoleStatement_ptr(new SQLDropRoleStatement());
  stmt->setDbType(dbType);

  SQLName_ptr name = this->exprParser->name();
  stmt->setName(name);

  return stmt;
}

SQLRevokeStatement_ptr SQLStatementParser::parseRevoke()
{
  LOG_INFO << "goto accept";
  accept(Token::REVOKE);

  SQLRevokeStatement_ptr stmt = SQLRevokeStatement_ptr(new SQLRevokeStatement(dbType));

  LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
  if (lexer->token()->name->c_str() == Token::GRANT.name->c_str())
  {
    lexer->nextToken();
    acceptIdentifier("OPTION");

    stmt->setGrantOption(BOOL::TRUE);

    if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
    {
      lexer->nextToken();
    }
  }

  parsePrivileages(stmt->getPrivileges(), stmt);

  LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
  if (lexer->token()->name->c_str() == Token::ON.name->c_str())
  {
    lexer->nextToken();

    LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
    if (lexer->token()->name->c_str() == Token::PROCEDURE.name->c_str())
    {
      lexer->nextToken();
      stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::PROCEDURE)));
    }
    else if (lexer->token()->name->c_str() == Token::FUNCTION.name->c_str())
    {
      lexer->nextToken();
      stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::FUNCTION)));
    }
    else if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
    {
      lexer->nextToken();
      stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::TABLE)));
    }
    else if (lexer->token()->name->c_str() == Token::USER.name->c_str())
    {
      lexer->nextToken();
      stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::USER)));
    }
    else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      WLOG_INFO << L"lexer text:" << lexer->stringVal()->c_str() << std::endl;
      if (lexer->identifierEquals(L"SYSTEM"))
      {
        lexer->nextToken();
        stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::SYSTEM)));
      }
      else if (lexer->identifierEquals(L"PROJECT"))
      {
        lexer->nextToken();
        stmt->setResourceType(SQLObjectType_ptr(new SQLObjectType(&SQLObjectType::PROJECT)));
      }
    }

    LOG_DEBUG << "goto this->exprParser->expr() dbType->name->c_str():" << dbType->name->c_str(); 
    SQLExpr_ptr expr = this->exprParser->expr();
    // expr =  std::dynamic_pointer_cast<MySqlExprParser>(this->exprParser)->expr();
    // expr = this->exprParser->expr();

    if (stmt->getResourceType() == nullptr ||
        stmt->getResourceType()->name == SQLObjectType::TABLE.name)
    {
      LOG_INFO << "if";
      stmt->setResource(SQLExprTableSource_ptr(new SQLExprTableSource(expr)));
    }
    else
    {
      LOG_INFO << "else";
      stmt->setResource(expr);
    }
  }

  LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
  if (lexer->token()->name->c_str() == Token::FROM.name->c_str())
  {
    lexer->nextToken();
    LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
    for (;;)
    {
      if (lexer->token()->name->c_str() == Token::USER.name->c_str() &&
          this->dbType == DbType_ptr(new DbType(&DbType::odps)))
      {
        lexer->nextToken();
        LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
      }
      SQLExpr_ptr user = parseUser();
      stmt->getUsers()->push_back(user);
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
        continue;
      }
      break;
    }
  }

  return stmt;
}

void SQLStatementParser::parsePrivileages(SQLPrivilegeItem_list_ptr privileges, SQLObject_ptr parent)
{
  LOG_INFO;
  for (;;)
  {
    string_ptr privilege;
    if (lexer->token()->name->c_str() == Token::ALL.name->c_str())
    {
      lexer->nextToken();
      if (lexer->identifierEquals(L"PRIVILEGES"))
      {
        privilege = make_string_ptr("ALL PRIVILEGES");
        lexer->nextToken();
      }
      else
      {
        privilege = make_string_ptr("ALL");
      }
    }
    else if (lexer->token()->name->c_str() == Token::SELECT.name->c_str())
    {
      privilege = make_string_ptr("SELECT");
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::UPDATE.name->c_str())
    {
      privilege = make_string_ptr("UPDATE");
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::DELETE.name->c_str())
    {
      privilege = make_string_ptr("DELETE");
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::INSERT.name->c_str())
    {
      privilege = make_string_ptr("INSERT");
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::INDEX.name->c_str())
    {
      lexer->nextToken();
      privilege = make_string_ptr("INDEX");
    }
    else if (lexer->token()->name->c_str() == Token::TRIGGER.name->c_str())
    {
      lexer->nextToken();
      privilege = make_string_ptr("TRIGGER");
    }
    else if (lexer->token()->name->c_str() == Token::REFERENCES.name->c_str())
    {
      privilege = make_string_ptr("REFERENCES");
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::DESC.name->c_str())
    {
      privilege = make_string_ptr("DESCRIBE");
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::CREATE.name->c_str())
    {
      lexer->nextToken();
      LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
      WLOG_INFO << L"lexer text:" << lexer->stringVal()->c_str() << std::endl;

      if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
      {
        privilege = make_string_ptr("CREATE TABLE");
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::SESSION.name->c_str())
      {
        privilege = make_string_ptr("CREATE SESSION");
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::TABLESPACE.name->c_str())
      {
        privilege = make_string_ptr("CREATE TABLESPACE");
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::USER.name->c_str())
      {
        privilege = make_string_ptr("CREATE USER");
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::VIEW.name->c_str())
      {
        privilege = make_string_ptr("CREATE VIEW");
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::PROCEDURE.name->c_str())
      {
        privilege = make_string_ptr("CREATE PROCEDURE");
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::SEQUENCE.name->c_str())
      {
        privilege = make_string_ptr("CREATE SEQUENCE");
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::ANY.name->c_str())
      {
        lexer->nextToken();

        if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
        {
          lexer->nextToken();
          privilege = make_string_ptr("CREATE ANY TABLE");
        }
        else if (lexer->identifierEquals(L"MATERIALIZED"))
        {
          lexer->nextToken();
          accept(Token::VIEW);
          privilege = make_string_ptr("CREATE ANY MATERIALIZED VIEW");
        }
        else
        {
          std::string tmp = "TODO ";
          tmp += lexer->token()->getName()->c_str();
          tmp += encode_util::UnicodeToUTF8(*lexer->stringVal()).c_str();
          throw new ParserException(make_string_ptr(tmp));
        }
      }
      else if (lexer->identifierEquals(L"SYNONYM"))
      {
        privilege = make_string_ptr("CREATE SYNONYM");
        lexer->nextToken();
      }
      else if (lexer->identifierEquals(L"ROUTINE"))
      {
        privilege = make_string_ptr("CREATE ROUTINE");
        lexer->nextToken();
      }
      else if (lexer->identifierEquals(L"TEMPORARY"))
      {
        lexer->nextToken();
        LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
        WLOG_INFO << L"lexer text:" << lexer->stringVal()->c_str() << std::endl;

        acceptIdentifier("TABLES");
        privilege = make_string_ptr("CREATE TEMPORARY TABLES");
      }
      else if (lexer->token()->name->c_str() == Token::ON.name->c_str())
      {
        privilege = make_string_ptr("CREATE");
      }
      else if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        privilege = make_string_ptr("CREATE");
      }
      else
      {
        std::string tmp = "TODO ";
        tmp += lexer->token()->getName()->c_str();
        tmp += encode_util::UnicodeToUTF8(*lexer->stringVal()).c_str();
        throw new ParserException(make_string_ptr(tmp));
      }
    }
    else if (lexer->token()->name->c_str() == Token::ALTER.name->c_str())
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
      {
        privilege = make_string_ptr("ALTER TABLE");
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::SESSION.name->c_str())
      {
        privilege = make_string_ptr("ALTER SESSION");
        lexer->nextToken();
      }
      else if (lexer->identifierEquals(FnvHash::Constants::ROUTINE))
      {
        privilege = make_string_ptr("ALTER ROUTINE");
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::ANY.name->c_str())
      {
        lexer->nextToken();

        if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
        {
          lexer->nextToken();
          privilege = make_string_ptr("ALTER ANY TABLE");
        }
        else if (lexer->identifierEquals(L"MATERIALIZED"))
        {
          lexer->nextToken();
          accept(Token::VIEW);
          privilege = make_string_ptr("ALTER ANY MATERIALIZED VIEW");
        }
        else
        {
          std::string tmp = "TODO ";
          tmp += lexer->token()->getName()->c_str();
          tmp += encode_util::UnicodeToUTF8(*lexer->stringVal()).c_str();
          throw new ParserException(make_string_ptr(tmp));
        }
      }
      else if (lexer->token()->name->c_str() == Token::ON.name->c_str() ||
               lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        privilege = make_string_ptr("ALTER");
      }
      else
      {
        std::string tmp = "TODO ";
        tmp += lexer->token()->getName()->c_str();
        tmp += encode_util::UnicodeToUTF8(*lexer->stringVal()).c_str();
        throw new ParserException(make_string_ptr(tmp));
      }
    }
    else if (lexer->token()->name->c_str() == Token::DROP.name->c_str())
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::DROP.name->c_str())
      {
        privilege = make_string_ptr("DROP TABLE");
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::SESSION.name->c_str())
      {
        privilege = make_string_ptr("DROP SESSION");
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::ANY.name->c_str())
      {
        lexer->nextToken();

        if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
        {
          lexer->nextToken();
          privilege = make_string_ptr("DROP ANY TABLE");
        }
        else if (lexer->identifierEquals(L"MATERIALIZED"))
        {
          lexer->nextToken();
          accept(Token::VIEW);
          privilege = make_string_ptr("DROP ANY MATERIALIZED VIEW");
        }
        else
        {
          std::string tmp = "TODO ";
          tmp += lexer->token()->getName()->c_str();
          tmp += encode_util::UnicodeToUTF8(*lexer->stringVal()).c_str();
          throw new ParserException(make_string_ptr(tmp));
        }
      }
      else
      {
        privilege = make_string_ptr("DROP");
      }
    }
    else if (lexer->identifierEquals(L"USAGE"))
    {
      privilege = make_string_ptr("USAGE");
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(L"EXECUTE"))
    {
      privilege = make_string_ptr("EXECUTE");
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(L"PROXY"))
    {
      privilege = make_string_ptr("PROXY");
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(L"QUERY"))
    {
      lexer->nextToken();
      acceptIdentifier("REWRITE");
      privilege = make_string_ptr("QUERY REWRITE");
    }
    else if (lexer->identifierEquals(L"GLOBAL"))
    {
      lexer->nextToken();
      acceptIdentifier("QUERY");
      acceptIdentifier("REWRITE");
      privilege = make_string_ptr("GLOBAL QUERY REWRITE");
    }
    else if (lexer->identifierEquals(L"INHERIT"))
    {
      lexer->nextToken();
      acceptIdentifier("PRIVILEGES");
      privilege = make_string_ptr("INHERIT PRIVILEGES");
    }
    else if (lexer->identifierEquals(L"EVENT"))
    {
      lexer->nextToken();
      privilege = make_string_ptr("EVENT");
    }
    else if (lexer->identifierEquals(L"FILE"))
    {
      lexer->nextToken();
      privilege = make_string_ptr("FILE");
    }
    else if (lexer->identifierEquals(L"DESCRIBE"))
    {
      lexer->nextToken();
      privilege = make_string_ptr("DESCRIBE");
    }
    else if (lexer->token()->name->c_str() == Token::GRANT.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("OPTION");

      if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
      {
        privilege = make_string_ptr("GRANT OPTION FOR");
        lexer->nextToken();
      }
      else
      {
        privilege = make_string_ptr("GRANT OPTION");
      }
    }
    else if (lexer->token()->name->c_str() == Token::LOCK.name->c_str())
    {
      lexer->nextToken();
      acceptIdentifier("TABLES");
      privilege = make_string_ptr("LOCK TABLES");
    }
    else if (lexer->identifierEquals(L"PROCESS"))
    {
      lexer->nextToken();
      privilege = make_string_ptr("PROCESS");
    }
    else if (lexer->identifierEquals(L"RELOAD"))
    {
      lexer->nextToken();
      privilege = make_string_ptr("RELOAD");
    }
    else if (lexer->identifierEquals(L"CONNECT"))
    {
      privilege = make_string_ptr("CONNECT");
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(L"RESOURCE"))
    {
      lexer->nextToken();
      privilege = make_string_ptr("RESOURCE");
    }
    else if (lexer->token()->name->c_str() == Token::CONNECT.name->c_str())
    {
      lexer->nextToken();
      privilege = make_string_ptr("CONNECT");
    }
    else if (lexer->identifierEquals(L"REPLICATION"))
    {
      lexer->nextToken();
      if (lexer->identifierEquals(L"SLAVE"))
      {
        lexer->nextToken();
        privilege = make_string_ptr("REPLICATION SLAVE");
      }
      else
      {
        acceptIdentifier("CLIENT");
        privilege = make_string_ptr("REPLICATION CLIENT");
      }
    }
    else if (lexer->token()->name->c_str() == Token::SHOW.name->c_str())
    {
      lexer->nextToken();

      if (lexer->token()->name->c_str() == Token::VIEW.name->c_str())
      {
        lexer->nextToken();
        privilege = make_string_ptr("SHOW VIEW");
      }
      else if (lexer->identifierEquals(L"DATABASES"))
      {
        acceptIdentifier("DATABASES");
        privilege = make_string_ptr("SHOW DATABASES");
      }
      else
      {
        privilege = make_string_ptr("SHOW");
      }
    }
    else if (lexer->identifierEquals(L"SHUTDOWN"))
    {
      lexer->nextToken();
      privilege = make_string_ptr("SHUTDOWN");
    }
    else if (lexer->identifierEquals(L"SUPER"))
    {
      lexer->nextToken();
      privilege = make_string_ptr("SUPER");
    }
    else if (lexer->identifierEquals(L"CONTROL"))
    { // sqlserver
      lexer->nextToken();
      privilege = make_string_ptr("CONTROL");
    }
    else if (lexer->identifierEquals(L"IMPERSONATE"))
    { // sqlserver
      lexer->nextToken();
      privilege = make_string_ptr("IMPERSONATE");
    }
    else if (lexer->identifierEquals(L"LOAD"))
    { // sqlserver
      lexer->nextToken();
      if (lexer->identifierEquals(L"DATA"))
      {
        lexer->nextToken();
        privilege = make_string_ptr("LOAD DATA");
      }
    }
    else if (lexer->identifierEquals(L"DUMP"))
    { // sqlserver
      lexer->nextToken();
      if (lexer->identifierEquals(L"DATA"))
      {
        lexer->nextToken();
        privilege = make_string_ptr("DUMP DATA");
      }
    }

    if (!privilege->empty())
    {
      SQLExpr_ptr expr = SQLExpr_ptr(new SQLIdentifierExpr(privilege));

      SQLPrivilegeItem_ptr privilegeItem = SQLPrivilegeItem_ptr(new SQLPrivilegeItem());
      privilegeItem->setAction(expr);
      LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
      WLOG_INFO << L",lexer text:" << lexer->stringVal()->c_str() << std::endl;

      if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
      {
        lexer->nextToken();
        for (;;)
        {
          privilegeItem->getColumns()->push_back(this->exprParser->name());

          if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
          {
            lexer->nextToken();
            continue;
          }
          break;
        }
        accept(Token::RPAREN);
      }

      expr->setParent((parent));
      privileges->push_back(privilegeItem);
    }

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    break;
  }
}

SQLExpr_ptr SQLStatementParser::parseUser()
{
  LOG_INFO << "goto expr";
  SQLExpr_ptr user = this->exprParser->expr();
  return user;
}

SQLSelectListCache_ptr SQLStatementParser::getSelectListCache()
{
  return selectListCache;
}

void SQLStatementParser::setSelectListCache(SQLSelectListCache_ptr selectListCache)
{
  this->selectListCache = selectListCache;
}

void SQLStatementParser::parseValueClauseNative(
    SQLInsertStatement_ValuesClause_list_ptr valueClauseList,
    SQLColumnDefinition_list_ptr columnDefinitionList,
    int columnSize,
    SQLObject_ptr parent)
{
  time_t timeZone = lexer->getTimeZone();
  SQLInsertStatement_ValuesClause_ptr values;
  for (int i = 0;; ++i)
  {
    int startPos = lexer->pos() - 1;

    if (lexer->token()->name != Token::LPAREN.name)
    {
      std::string tmp = "syntax error, expect ')', ";
      tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
      throw new ParserException(make_string_ptr(tmp));
    }
    //            lexer->nextTokenValue();

    if (lexer->ch == L'\'')
    { // for performance
      lexer->bufPos = 0;
      if (dbType->name == DbType::mysql.name)
      {
        lexer->scanString2();
      }
      else
      {
        lexer->scanString();
      }
    }
    else if (lexer->ch == L'0')
    {
      lexer->bufPos = 0;
      if (lexer->charAt(lexer->pos() + 1) == L'x')
      {
        lexer->scanChar();
        lexer->scanChar();
        lexer->scanHexaDecimal();
      }
      else
      {
        lexer->scanNumber();
      }
    }
    else if (lexer->ch > L'0' && lexer->ch <= L'9')
    {
      lexer->bufPos = 0;
      lexer->scanNumber();
    }
    else if (lexer->ch == L'-' && lexer->charAt(lexer->pos() + 1) != L'-')
    {
      lexer->scanNumber();
    }
    else
    {
      lexer->nextTokenValue();
    }

    if (lexer->token()->name != Token::RPAREN.name)
    {
      SQLExpr_list_ptr valueExprList = std::make_shared<std::list<SQLExpr_ptr>>();
      // if (columnSize > 0)
      // {
      //   valueExprList = new ArrayList(columnSize);
      // }
      // else
      // {
      //   valueExprList = new ArrayList();
      // }
      values = SQLInsertStatement_ValuesClause_ptr(new SQLInsertStatement_ValuesClause(valueExprList, parent));

      int funcExecCount = 0;
      auto it_columnDefinitionList = columnDefinitionList->begin();
      for (int j = 0;; ++j)
      {
        SQLExpr_ptr expr = nullptr;
        Object_ptr value = Object_ptr(new Object());

        SQLColumnDefinition_ptr columnDefinition = nullptr;
        if (columnDefinitionList != nullptr && j < columnDefinitionList->size())
        {
          std::advance(it_columnDefinitionList, j);
          columnDefinition = *it_columnDefinitionList;
        }

        SQLDataType_ptr dataType = nullptr;
        if (columnDefinition != nullptr)
        {
          dataType = columnDefinition->getDataType();
        }

        if (lexer->token()->name == Token::LITERAL_INT.name)
        {
          long integerValue = lexer->integerValue();

          if (lexer->ch == L',')
          {
            lexer->ch = lexer->charAt(++lexer->pos_);
            lexer->token_ = Token_ptr(new Token(&Token::COMMA));
          }
          else
          {
            lexer->nextTokenCommaValue();
          }

          if (lexer->token_->name != Token::COMMA.name && lexer->token()->name != Token::RPAREN.name)
          {
            expr = SQLIntegerExpr_ptr(new SQLIntegerExpr(integerValue, values));
            expr = this->exprParser->exprRest(expr);
            expr->setParent(values);
          }
          else
          {
            value->any_data_ = integerValue;
          }
          break;
        }
        else if (lexer->token()->name == Token::LITERAL_CHARS.name)
        {
          string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));

          if (lexer->ch == L',')
          {
            lexer->ch = lexer->charAt(++(lexer->pos_));
            lexer->token_ = Token_ptr(new Token(&Token::COMMA));
          }
          else
          {
            lexer->nextTokenCommaValue();
          }

          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            expr = SQLCharExpr_ptr(new SQLCharExpr(strVal, values));
            expr = this->exprParser->exprRest(expr);
            expr->setParent(values);
          }
          else
          {
            value->any_data_ = strVal->c_str();
          }
          break;
        }
        if (lexer->token()->name == Token::LITERAL_NCHARS.name)
        {
          string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));

          if (lexer->ch == L',')
          {
            lexer->ch = lexer->charAt(++(lexer->pos_));
            lexer->token_ = Token_ptr(new Token(&Token::COMMA));
          }
          else
          {
            lexer->nextTokenCommaValue();
          }

          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            expr = SQLNCharExpr_ptr(new SQLNCharExpr(strVal, values));
            expr = this->exprParser->exprRest(expr);
            expr->setParent(values);
          }
          else
          {
            value->any_data_ = strVal->c_str();
          }
          break;
        }
        if (lexer->token()->name == Token::LITERAL_FLOAT.name)
        {
          BigDecimal number = lexer->decimalValue();

          if (dataType != nullptr && dataType->nameHashCode64() == FnvHash::Constants::DECIMAL)
          {
            int precision = 0, scale = 0;
            SQLExpr_list_ptr arguments = dataType->getArguments();
            auto it_arguments = arguments->begin();
            if (arguments->size() > 0)
            {
              std::advance(it_arguments, 0);
              SQLExpr_ptr arg0 = *it_arguments;
              if (instanceof <SQLExpr, SQLIntegerExpr>(arg0))
              {
                precision = (std::dynamic_pointer_cast<SQLIntegerExpr>(arg0))->getNumber();
              }
            }
            if (arguments->size() > 1)
            {
              std::advance(it_arguments, 1);
              SQLExpr_ptr arg0 = *it_arguments;
              if (instanceof <SQLExpr, SQLIntegerExpr>(arg0))
              {
                scale = (std::dynamic_pointer_cast<SQLIntegerExpr>(arg0))->getNumber();
              }
            }

            // if (number instanceof BigDecimal)
            // {
            // number = MySqlUtils::decimal(number, precision, scale);
            // }
          }

          if (lexer->ch == L',')
          {
            lexer->ch = lexer->charAt(++(lexer->pos_));
            lexer->token_ = Token_ptr(new Token(&Token::COMMA));
          }
          else
          {
            lexer->nextTokenCommaValue();
          }

          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            expr = SQLDecimalExpr_ptr(new SQLDecimalExpr(make_string_ptr(number.toString())));
            expr = this->exprParser->exprRest(expr);
            expr->setParent(values);
          }
          else
          {
            value->any_data_ = number.toString();
          }
          break;
        }
        if (lexer->token()->name == Token::XNULL.name)
        {
          lexer->nextTokenCommaValue();
          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            expr = SQLNullExpr_ptr(new SQLNullExpr(parent));
            expr = this->exprParser->exprRest(expr);
            expr->setParent(values);
          }
          else
          {
            value = nullptr;
          }
          break;
        }
        if (lexer->token()->name == Token::IDENTIFIER.name)
        {
          long hash = lexer->hashLCase();
          if (hash == FnvHash::Constants::DATE)
          {
            lexer->nextTokenValue();
            string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
            // value = java.sql.Date.valueOf(strVal);
            lexer->nextTokenComma();
          }
          else if (hash == FnvHash::Constants::TIMESTAMP &&
                   timeZone != 0 /*nullptr*/)
          {
            lexer->nextTokenValue();
            string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
            // value = new java.sql.Timestamp(MySqlUtils.parseDate(strVal, timeZone).getTime());
            lexer->nextTokenComma();
          }
          else if (hash == FnvHash::Constants::CURDATE ||
                   hash == FnvHash::Constants::CUR_DATE ||
                   hash == FnvHash::Constants::CURRENT_DATE)
          {
            lexer->nextTokenValue();

            if (lexer->token()->name == Token::LPAREN.name)
            {
              lexer->nextToken();
              accept(Token::RPAREN);
            }

            if (now == 0 /*nullptr*/)
            {
              // now = new java.sql.Timestamp(System.currentTimeMillis());
            }

            if (currentDate == 0 /*nullptr*/)
            {
              // currentDate = new java.sql.Date(now.getTime());
            }
            value->any_data_ = currentDate;
            funcExecCount++;
          }
          else if ((hash == FnvHash::Constants::SYSDATE ||
                    hash == FnvHash::Constants::NOW ||
                    hash == FnvHash::Constants::CURRENT_TIMESTAMP) &&
                   timeZone != 0 /*nullptr*/)
          {
            lexer->nextTokenValue();

            if (lexer->token()->name == Token::LPAREN.name)
            {
              lexer->nextToken();
              accept(Token::RPAREN);
            }

            if (now == 0 /*nullptr*/)
            {
              // now = new java.sql.Timestamp(System.currentTimeMillis());
            }
            value->any_data_ = now;
            funcExecCount++;
          }
          else if (hash == FnvHash::Constants::UUID)
          {
            lexer->nextTokenLParen();
            accept(Token::LPAREN);
            accept(Token::RPAREN);
            value->any_data_ = UUID::generate_uuid();
            funcExecCount++;
          }
          else
          {
            value = nullptr;
            Lexer_SavePoint_ptr mark = lexer->mark();
            expr = exprParser->expr();
            if (instanceof <SQLExpr, SQLName>(expr))
            {
              lexer->reset(mark);
              lexer->info();
              std::stringstream ss;
              ss << "insert value error, token ";
              ss << lexer->stringVal()->c_str();
              ss << ", line ";
              ss << lexer->posLine;
              ss << ", column ";
              ss << lexer->posColumn;
              ss << lexer->posLine;
              ss << lexer->posColumn;
              throw new ParserException(make_string_ptr(ss.str()));
            }
            expr->setParent(values);
          }
          break;
        }
        else
        {
          value = nullptr;
          expr = exprParser->expr();
          expr->setParent(values);
          break;
        }

        if (expr != nullptr)
        {
          expr->setParent(values);
          value = expr;
        }

        if (lexer->token()->name == Token::COMMA.name)
        {
          valueExprList->push_back(std::dynamic_pointer_cast<SQLExpr>(value));

          if (lexer->ch == L'\'')
          { // for performance
            lexer->bufPos = 0;
            if (dbType->name == DbType::mysql.name)
            {
              lexer->scanString2();
            }
            else
            {
              lexer->scanString();
            }
          }
          else if (lexer->ch == L'0')
          {
            lexer->bufPos = 0;
            if (lexer->charAt(lexer->pos_ + 1) == L'x')
            {
              lexer->scanChar();
              lexer->scanChar();
              lexer->scanHexaDecimal();
            }
            else
            {
              lexer->scanNumber();
            }
          }
          else if (lexer->ch > L'0' && lexer->ch <= L'9')
          {
            lexer->bufPos = 0;
            lexer->scanNumber();
          }
          else if (lexer->ch == L'-' &&
                   lexer->charAt(lexer->pos_ + 1) != L'-')
          {
            lexer->bufPos = 0;
            lexer->scanNumber();
          }
          else
          {
            lexer->nextTokenValue();
          }
          continue;
        }
        else if (lexer->token()->name == Token::RPAREN.name)
        {
          valueExprList->push_back(std::dynamic_pointer_cast<SQLExpr>(value));
          break;
        }
        else
        {
          expr = this->exprParser->primaryRest(expr);
          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            expr = this->exprParser->exprRest(expr);
          }
          expr->setParent(values);

          valueExprList->push_back(expr);
          if (lexer->token()->name == Token::COMMA.name)
          {
            lexer->nextTokenValue();
            continue;
          }
          else
          {
            break;
          }
        }
      }

      if (funcExecCount == 0 &&
          lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::KeepInsertValueClauseOriginalString))))
      {
        int endPos = lexer->pos();
        string_ptr orginalString = make_string_ptr(encode_util::UnicodeToUTF8(lexer->subString(startPos, endPos - startPos)));
        values->setOriginalString(orginalString);
      }
    }
    else
    {
      SQLExpr_list_ptr tmp = std::make_shared<std::list<SQLExpr_ptr>>();
      values = SQLInsertStatement_ValuesClause_ptr(new SQLInsertStatement_ValuesClause(tmp));
    }

    valueClauseList->push_back(values);

    if (lexer->token()->name != Token::RPAREN.name)
    {
      std::stringstream ss;
      ss << "syntax error. ";
      ss << encode_util::UnicodeToUTF8(lexer->info());
      throw new ParserException(make_string_ptr(ss.str()));
    }

    if (!parseCompleteValues && valueClauseList->size() >= parseValuesSize)
    {
      lexer->skipToEOF();
      break;
    }

    lexer->nextTokenComma();
    if (lexer->token()->name == Token::COMMA.name)
    {
      lexer->nextTokenLParen();
      if (values != nullptr)
      {
        columnSize = values->getValues()->size();
      }
      continue;
    }
    else
    {
      break;
    }
  }
}

void SQLStatementParser::parseValueClause(
    SQLInsertStatement_ValuesClause_list_ptr valueClauseList,
    int columnSize,
    SQLObject_ptr parent)
{
  parseValueClause(valueClauseList, nullptr, 0, parent);
}

void SQLStatementParser::parseValueClause(SQLInsertValueHandler_ptr valueHandler)
{
  for (;;)
  {
    if (lexer->token()->name != Token::LPAREN.name)
    {
      std::stringstream ss;
      ss << "syntax error, expect ')', ";
      ss << encode_util::UnicodeToUTF8(lexer->info());
      throw new ParserException(make_string_ptr(ss.str()));
    }

    if (lexer->ch == L'\'')
    { // for performance
      lexer->bufPos = 0;
      if (dbType->name == DbType::mysql.name)
      {
        lexer->scanString2();
      }
      else
      {
        lexer->scanString();
      }
    }
    else if (lexer->ch == L'0')
    {
      lexer->bufPos = 0;
      if (lexer->charAt(lexer->pos_ + 1) == L'x')
      {
        lexer->scanChar();
        lexer->scanChar();
        lexer->scanHexaDecimal();
      }
      else
      {
        lexer->scanNumber();
      }
    }
    else if (lexer->ch > L'0' &&
             lexer->ch <= L'9')
    {
      lexer->bufPos = 0;
      lexer->scanNumber();
    }
    else if (lexer->ch == L'-' &&
             lexer->charAt(lexer->pos_ + 1) != L'-')
    {
      lexer->scanNumber();
    }
    else
    {
      lexer->nextTokenValue();
    }

    if (lexer->token()->name != Token::RPAREN.name)
    {
      Object_ptr row = valueHandler->newRow();

      for (int j = 0;; ++j)
      {
        if (lexer->token()->name == Token::LITERAL_INT.name)
        {
          long number = lexer->integerValue();

          if (lexer->ch == L',')
          {
            lexer->ch = lexer->charAt(++(lexer->pos_));
            lexer->token_ = Token_ptr(new Token(&Token::COMMA));
          }
          else
          {
            lexer->nextTokenCommaValue();
          }

          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            std::stringstream ss;
            ss << "insert value error, ";
            ss << encode_util::UnicodeToUTF8(lexer->info());
            throw new ParserException(make_string_ptr(ss.str()));
          }

          valueHandler->processInteger(row, j, number);
          // break;
        }
        else if (lexer->token()->name == Token::LITERAL_CHARS.name ||
                 lexer->token()->name == Token::LITERAL_NCHARS.name)
        {
          string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));

          if (lexer->ch == L',')
          {
            lexer->ch = lexer->charAt(++(lexer->pos_));
            lexer->token_ = Token_ptr(new Token(&Token::COMMA));
          }
          else
          {
            lexer->nextTokenCommaValue();
          }

          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            std::stringstream ss;
            ss << "insert value error, ";
            ss << encode_util::UnicodeToUTF8(lexer->info());
            throw new ParserException(make_string_ptr(ss.str()));
          }

          valueHandler->processString(row, j, strVal);
          // break;
        }
        else if (lexer->token()->name == Token::LITERAL_FLOAT.name)
        {
          BigDecimal number = lexer->decimalValue();

          if (lexer->ch == L',')
          {
            lexer->ch = lexer->charAt(++(lexer->pos_));
            lexer->token_ = Token_ptr(new Token(&Token::COMMA));
          }
          else
          {
            lexer->nextTokenCommaValue();
          }

          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            std::stringstream ss;
            ss << "insert value error, ";
            ss << encode_util::UnicodeToUTF8(lexer->info()).c_str();
            throw new ParserException(make_string_ptr(ss.str()));
          }

          valueHandler->processDecimal(row, j, number);
          // break;
        }
        else if (lexer->token()->name == Token::XNULL.name)
        {
          lexer->nextTokenCommaValue();
          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            std::stringstream ss;
            ss << "insert value error, ";
            ss << encode_util::UnicodeToUTF8(lexer->info()).c_str();
            throw new ParserException(make_string_ptr(ss.str()));
          }

          valueHandler->processNull(row, j);
          break;
        }
        else if (lexer->token()->name == Token::XTRUE.name)
        {
          valueHandler->processBoolean(row, j, BOOL::TRUE);
          lexer->nextTokenComma();
        }
        else if (lexer->token()->name == Token::XFALSE.name)
        {
          valueHandler->processBoolean(row, j, BOOL::FALSE);
          lexer->nextTokenComma();
        }
        else if (lexer->token()->name == Token::IDENTIFIER.name)
        {
          long hash = lexer->hashLCase();
          if (hash == FnvHash::Constants::DATE)
          {
            lexer->nextTokenValue();
            string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
            valueHandler->processDate(row, j, strVal);
            lexer->nextTokenComma();
          }
          else if (hash == FnvHash::Constants::TIMESTAMP)
          {
            lexer->nextTokenValue();
            string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
            valueHandler->processTimestamp(row, j, strVal);
            lexer->nextTokenComma();
          }
          else if (hash == FnvHash::Constants::TIME)
          {
            lexer->nextTokenValue();
            string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
            valueHandler->processTime(row, j, strVal);
            lexer->nextTokenComma();
          }
          else if (hash == FnvHash::Constants::DECIMAL)
          {
            lexer->nextTokenValue();
            string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
            BigDecimal decimal = BigDecimal(strVal->c_str());
            valueHandler->processDecimal(row, j, decimal);
            lexer->nextTokenComma();
          }
          else if (hash == FnvHash::Constants::CURDATE ||
                   hash == FnvHash::Constants::CUR_DATE ||
                   hash == FnvHash::Constants::CURRENT_DATE ||
                   hash == FnvHash::Constants::SYSDATE)
          {
            lexer->nextTokenLParen();

            if (lexer->token()->name == Token::LPAREN.name)
            {
              lexer->nextToken();
              accept(Token::RPAREN);
            }

            if (currentDate == 0 /*nullptr*/)
            {
              // currentDate = new java.sql.Date(now.getTime());
            }

            // valueHandler->processDate(row, j, currentDate);
          }
          else if (hash == FnvHash::Constants::NOW || hash == FnvHash::Constants::CURRENT_TIMESTAMP)
          {
            lexer->nextTokenLParen();

            if (lexer->token()->name == Token::LPAREN.name)
            {
              lexer->nextToken();
              accept(Token::RPAREN);
            }

            if (now == 0 /*nullptr*/)
            {
              // now = new java.sql.Timestamp(System.currentTimeMillis());
            }

            // valueHandler->processTimestamp(row, j, now);
          }
          else if (hash == FnvHash::Constants::UUID)
          {
            string_ptr funcName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
            lexer->nextTokenLParen();

            if (lexer->token()->name == Token::LPAREN.name)
            {
              lexer->nextToken();
              accept(Token::RPAREN);
            }
            else
            {
              std::stringstream ss;
              ss << "insert value error, ";
              ss << encode_util::UnicodeToUTF8(lexer->info()).c_str();
              throw new ParserException(make_string_ptr(ss.str()));
            }

            if (now == 0 /*nullptr*/)
            {
              // now = new java.sql.Timestamp(System.currentTimeMillis());
            }

            // valueHandler->processFunction(row, j, funcName, hash);
          }
          else if (hash == FnvHash::Constants::STR_TO_DATE ||
                   hash == FnvHash::Constants::DATE_PARSE)
          {
            string_ptr funcName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
            lexer->nextTokenLParen();

            string_ptr strVal, format;
            if (lexer->token()->name == Token::LPAREN.name)
            {
              lexer->nextTokenValue();
              strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
              lexer->nextTokenComma();
              accept(Token::COMMA);
              format = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
              lexer->nextTokenValue();
              accept(Token::RPAREN);
            }
            else
            {
              std::stringstream ss;
              ss << "insert value error, ";
              ss << encode_util::UnicodeToUTF8(lexer->info()).c_str();
              throw new ParserException(make_string_ptr(ss.str()));
            }

            string_list_ptr tmp = std::make_shared<std::list<string_ptr>>();
            tmp->push_back(strVal);
            tmp->push_back(format);
            valueHandler->processFunction(row, j, funcName, hash, tmp);
          }
          else if (FnvHash::Constants::CLOTHES_FEATURE_EXTRACT_V1 == hash ||
                   FnvHash::Constants::CLOTHES_ATTRIBUTE_EXTRACT_V1 == hash ||
                   FnvHash::Constants::GENERIC_FEATURE_EXTRACT_V1 == hash ||
                   FnvHash::Constants::TEXT_FEATURE_EXTRACT_V1 == hash ||
                   FnvHash::Constants::FACE_FEATURE_EXTRACT_V1 == hash)
          {
            string_ptr funcName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
            lexer->nextTokenLParen();

            string_ptr urlVal;
            if (Token::LPAREN.name == lexer->token()->name)
            {
              lexer->nextTokenValue();
              urlVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
              lexer->nextToken();
              accept(Token::RPAREN);
            }
            else
            {
              std::stringstream ss;
              ss << "insert value error, ";
              ss << encode_util::UnicodeToUTF8(lexer->info()).c_str();
              throw new ParserException(make_string_ptr(ss.str()));
            }

            string_list_ptr tmp = std::make_shared<std::list<string_ptr>>();
            tmp->push_back(urlVal);
            valueHandler->processFunction(row, j, funcName, hash, tmp);
          }
          else
          {
            std::stringstream ss;
            ss << "insert value error, ";
            ss << encode_util::UnicodeToUTF8(lexer->info()).c_str();
            throw new ParserException(make_string_ptr(ss.str()));
          }
          break;
        }
        else
        {
          std::stringstream ss;
          ss << "insert value error, ";
          ss << encode_util::UnicodeToUTF8(lexer->info()).c_str();
          throw new ParserException(make_string_ptr(ss.str()));
        }

        if (lexer->token()->name == Token::COMMA.name)
        {
          if (lexer->ch == L'\'')
          { // for performance
            lexer->bufPos = 0;
            if (dbType->name == DbType::mysql.name)
            {
              lexer->scanString2();
            }
            else
            {
              lexer->scanString();
            }
          }
          else if (lexer->ch == L'0')
          {
            lexer->bufPos = 0;
            if (lexer->charAt(lexer->pos_ + 1) == L'x')
            {
              lexer->scanChar();
              lexer->scanChar();
              lexer->scanHexaDecimal();
            }
            else
            {
              lexer->scanNumber();
            }
          }
          else if (lexer->ch > L'0' &&
                   lexer->ch <= L'9')
          {
            lexer->bufPos = 0;
            lexer->scanNumber();
          }
          else if (lexer->ch == L'-' &&
                   lexer->charAt(lexer->pos_ + 1) != L'-')
          {
            lexer->bufPos = 0;
            lexer->scanNumber();
          }
          else
          {
            lexer->nextTokenValue();
          }
          continue;
        }
        else if (lexer->token()->name == Token::RPAREN.name)
        {
          break;
        }
        else
        {
          std::stringstream ss;
          ss << "insert value error, ";
          ss << encode_util::UnicodeToUTF8(lexer->info()).c_str();
          throw new ParserException(make_string_ptr(ss.str()));
          //
          //                        if (lexer->token == Token::COMMA) {
          //                            lexer->nextTokenValue();
          //                            continue;
          //                        } else {
          //                            break;
          //                        }
        }
      } // for j

      valueHandler->processRow(row);
    }

    if (lexer->token()->name != Token::RPAREN.name)
    {
      std::stringstream ss;
      ss << "syntax error. ";
      ss << encode_util::UnicodeToUTF8(lexer->info()).c_str();
      throw new ParserException(make_string_ptr(ss.str()));
    }

    lexer->nextTokenComma();
    if (lexer->token()->name == Token::COMMA.name)
    {
      lexer->nextTokenLParen();
      continue;
    }
    else
    {
      valueHandler->processComplete();
      break;
    }
  }
}

void SQLStatementParser::parseValueClause(
    SQLInsertStatement_ValuesClause_list_ptr valueClauseList,
    SQLColumnDefinition_list_ptr columnDefinitionList,
    int columnSize,
    SQLObject_ptr parent)
{
  BOOL_ptr optimizedForParameterized = lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::OptimizedForForParameterizedSkipValue)));

  SQLInsertStatement_ValuesClause_ptr values = nullptr;
  for (int i = 0;; ++i)
  {
    int startPos = lexer->pos_ - 1;

    LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str() << "lexer->stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_).c_str();
    LOG_INFO << "startPos:" << startPos;

    if (lexer->token()->name == Token::ROW.name)
    {
      lexer->nextToken();
    }
    if (lexer->token()->name != Token::LPAREN.name)
    {
      std::stringstream ss;
      ss << "syntax error, expect ')', ";
      ss << encode_util::UnicodeToUTF8(lexer->info()).c_str();
      throw new ParserException(make_string_ptr(ss.str()));
    }

    LOG_INFO << "lexer->ch->at(0):" << lexer->ch;
    if (lexer->ch == L'\'')
    { // for performance
      lexer->bufPos = 0;
      LOG_INFO << "DbType::mysql.name:" << DbType::mysql.name->c_str();
      if (dbType == nullptr)
      {
        LOG_INFO << "dbType == nullptr";
      }
      else
      {
        LOG_INFO << "dbType->name:" << dbType->name->c_str();
      }
      if (dbType->name->c_str() == DbType::mysql.name->c_str())
      {
        LOG_INFO << "goto scanString2";
        lexer->scanString2();
      }
      else
      {
        LOG_INFO << "goto scanString";
        lexer->scanString();
      }
    }
    else if (lexer->ch == L'0')
    {
      lexer->bufPos = 0;
      if (lexer->charAt(lexer->pos_ + 1) == L'x')
      {
        lexer->scanChar();
        lexer->scanChar();
        lexer->scanHexaDecimal();
      }
      else
      {
        lexer->scanNumber();
      }
    }
    else if (lexer->ch > L'0' && lexer->ch <= L'9')
    {
      lexer->bufPos = 0;
      lexer->scanNumber();
    }
    else if (lexer->ch == L'-' && lexer->charAt(lexer->pos_ + 1) != L'-')
    {
      lexer->bufPos = 0;
      lexer->scanNumber();
    }
    else
    {
      LOG_INFO << "goto nextTokenValue";
      lexer->nextTokenValue();
    }

    LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str() << "lexer->stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_).c_str();
    if (lexer->token()->name != Token::RPAREN.name)
    {
      SQLExpr_list_ptr valueExprList = std::make_shared<std::list<SQLExpr_ptr>>();
      // if (columnSize > 0)
      // {
      //   valueExprList = new ArrayList(columnSize);
      // }
      // else
      // {
      //   valueExprList = new ArrayList();
      // }
      values = SQLInsertStatement_ValuesClause_ptr(new SQLInsertStatement_ValuesClause(valueExprList, parent));

      for (int j = 0;; ++j)
      {
        SQLExpr_ptr expr;

        SQLColumnDefinition_ptr columnDefinition = nullptr;
        if (columnDefinitionList != nullptr && j < columnDefinitionList->size())
        {
          auto it_columnDefinitionList = columnDefinitionList->begin();
          std::advance(it_columnDefinitionList, j);
          columnDefinition = *it_columnDefinitionList;
        }

        SQLDataType_ptr dataType = nullptr;
        if (columnDefinition != nullptr)
        {
          dataType = columnDefinition->getDataType();
        }

        if (lexer->token()->name == Token::LITERAL_INT.name)
        {
          if (optimizedForParameterized)
          {
            expr = SQLVariantRefExpr_ptr(new SQLVariantRefExpr(make_string_ptr("?"), values));
            values->incrementReplaceCount();
          }
          else
          {
            expr = SQLIntegerExpr_ptr(new SQLIntegerExpr(lexer->integerValue(), values));
          }
          if (lexer->ch == L',')
          {
            lexer->ch = lexer->charAt(++(lexer->pos_));
            lexer->token_ = Token_ptr(new Token(&Token::COMMA));
          }
          else
          {
            lexer->nextTokenCommaValue();
          }

          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            expr = this->exprParser->exprRest(expr);
            expr->setParent(values);
          }
        }
        else if (lexer->token()->name == Token::LITERAL_CHARS.name)
        {
          if (optimizedForParameterized)
          {
            expr = SQLVariantRefExpr_ptr(new SQLVariantRefExpr(make_string_ptr("?"), values));
            values->incrementReplaceCount();
          }
          else
          {
            expr = SQLCharExpr_ptr(new SQLCharExpr(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())), values));
          }

          if (lexer->ch == L',')
          {
            lexer->ch = lexer->charAt(++(lexer->pos_));
            lexer->token_ = Token_ptr(new Token(&Token::COMMA));
          }
          else
          {
            lexer->nextTokenCommaValue();
          }

          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            expr = this->exprParser->exprRest(expr);
            expr->setParent(values);
          }
        }
        else if (lexer->token()->name == Token::LITERAL_NCHARS.name)
        {
          if (optimizedForParameterized)
          {
            expr = SQLVariantRefExpr_ptr(new SQLVariantRefExpr(make_string_ptr("?"), values));
            values->incrementReplaceCount();
          }
          else
          {
            expr = SQLNCharExpr_ptr(new SQLNCharExpr(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())), values));
          }

          if (lexer->ch == L',')
          {
            lexer->ch = lexer->charAt(++(lexer->pos_));
            lexer->token_ = Token_ptr(new Token(&Token::COMMA));
          }
          else
          {
            lexer->nextTokenCommaValue();
          }

          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            expr = this->exprParser->exprRest(expr);
            expr->setParent(values);
          }
        }
        else if (lexer->token()->name == Token::LITERAL_FLOAT.name)
        {
          if (optimizedForParameterized)
          {
            expr = SQLVariantRefExpr_ptr(new SQLVariantRefExpr(make_string_ptr("?"), values));
            values->incrementReplaceCount();
          }
          else
          {
            SQLNumberExpr_ptr numberExpr = lexer->numberExpr(parent);

            if (dataType != nullptr &&
                dataType->nameHashCode64() == FnvHash::Constants::DECIMAL)
            {
              double number = numberExpr->getNumber();

              int precision = 0, scale = 0;
              SQLExpr_list_ptr arguments = dataType->getArguments();
              auto it_arguments = arguments->begin();
              if (arguments->size() > 0)
              {
                std::advance(it_arguments, 0);
                SQLExpr_ptr arg0 = *(it_arguments);
                if (instanceof <SQLExpr, SQLIntegerExpr>(arg0))
                {
                  precision = (std::dynamic_pointer_cast<SQLIntegerExpr>(arg0))->getNumber();
                }
              }
              if (arguments->size() > 1)
              {
                std::advance(it_arguments, 1);
                SQLExpr_ptr arg0 = *(it_arguments);
                if (instanceof <SQLExpr, SQLIntegerExpr>(arg0))
                {
                  scale = (std::dynamic_pointer_cast<SQLIntegerExpr>(arg0))->getNumber();
                }
              }

              // if (number instanceof BigDecimal)
              // {
              //   number = MySqlUtils.decimal((BigDecimal)number, precision, scale);
              //   numberExpr.setNumber(number);
              // }
            }

            expr = numberExpr;
          }

          if (lexer->ch == L',')
          {
            lexer->ch = lexer->charAt(++(lexer->pos_));
            lexer->token_ = Token_ptr(new Token(&Token::COMMA));
          }
          else
          {
            lexer->nextTokenCommaValue();
          }

          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            expr = this->exprParser->exprRest(expr);
            expr->setParent(values);
          }
        }
        else if (lexer->token()->name == Token::XNULL.name)
        {
          if (optimizedForParameterized)
          {
            expr = SQLVariantRefExpr_ptr(new SQLVariantRefExpr(make_string_ptr("?"), parent));
            values->incrementReplaceCount();
          }
          else
          {
            expr = SQLNullExpr_ptr(new SQLNullExpr(parent));
          }
          lexer->nextTokenCommaValue();
          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            expr = this->exprParser->exprRest(expr);
            expr->setParent(values);
          }
        }
        else
        {
          expr = exprParser->expr();
          expr->setParent(values);
        }

        if (lexer->token()->name == Token::COMMA.name)
        {
          valueExprList->push_back(expr);

          if (lexer->ch == L'\'')
          { // for performance
            lexer->bufPos = 0;
            if (dbType->name == DbType::mysql.name)
            {
              lexer->scanString2();
            }
            else
            {
              lexer->scanString();
            }
          }
          else if (lexer->ch == L'0')
          {
            lexer->bufPos = 0;
            if (lexer->charAt(lexer->pos_ + 1) == L'x')
            {
              lexer->scanChar();
              lexer->scanChar();
              lexer->scanHexaDecimal();
            }
            else
            {
              lexer->scanNumber();
            }
          }
          else if (lexer->ch > L'0' &&
                   lexer->ch <= L'9')
          {
            lexer->bufPos = 0;
            lexer->scanNumber();
          }
          else if (lexer->ch == L'-' &&
                   lexer->charAt(lexer->pos_ + 1) != L'-')
          {
            lexer->bufPos = 0;
            lexer->scanNumber();
          }
          else
          {
            lexer->nextTokenValue();
          }
          continue;
        }
        else if (lexer->token()->name == Token::RPAREN.name)
        {
          valueExprList->push_back(expr);
          break;
        }
        else
        {
          expr = this->exprParser->primaryRest(expr);
          if (lexer->token()->name != Token::COMMA.name &&
              lexer->token()->name != Token::RPAREN.name)
          {
            expr = this->exprParser->exprRest(expr);
          }
          expr->setParent(values);

          valueExprList->push_back(expr);
          if (lexer->token()->name == Token::COMMA.name)
          {
            lexer->nextTokenValue();
            continue;
          }
          else
          {
            break;
          }
        }
      }

      if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::KeepInsertValueClauseOriginalString))))
      {
        int endPos = lexer->pos();
        string_ptr orginalString = make_string_ptr(encode_util::UnicodeToUTF8(lexer->subString(startPos, endPos - startPos)));
        values->setOriginalString(orginalString);
      }
    }
    else
    {
      SQLExpr_list_ptr tmp = std::make_shared<std::list<SQLExpr_ptr>>();
      values = SQLInsertStatement_ValuesClause_ptr(new SQLInsertStatement_ValuesClause(tmp));
    }

    valueClauseList->push_back(values);

    LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str() << "lexer->stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_).c_str();
    if (lexer->token()->name != Token::RPAREN.name)
    {
      std::stringstream ss;
      ss << "syntax error. ";
      ss << encode_util::UnicodeToUTF8(lexer->info()).c_str();
      throw new ParserException(make_string_ptr(ss.str()));
    }

    if (!parseCompleteValues && valueClauseList->size() >= parseValuesSize)
    {
      lexer->skipToEOF();
      break;
    }

    lexer->nextTokenComma();

    LOG_INFO << "lexer->token->name:" << lexer->token()->getName()->c_str() << "lexer->stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_).c_str();
    if (lexer->token()->name == Token::COMMA.name)
    {
      lexer->nextTokenLParen();
      if (values != nullptr)
      {
        columnSize = values->getValues()->size();
      }
      continue;
    }
    else
    {
      break;
    }
  }
}

void SQLStatementParser::parseHints(SQLHint_list_ptr hints)
{
  this->getExprParser()->parseHints(hints);
}

SQLStatement_ptr SQLStatementParser::parseMerge()
{
  if (lexer->identifierEquals(FnvHash::Constants::MERGE))
  {
    lexer->nextToken();
  }
  else
  {
    accept(Token::MERGE);
  }

  SQLMergeStatement_ptr stmt = SQLMergeStatement_ptr(new SQLMergeStatement());
  stmt->setDbType(dbType);

  parseHints(stmt->getHints());

  accept(Token::INTO);

  if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    lexer->nextToken();
    SQLSelect_ptr select = this->createSQLSelectParser()->select();
    SQLSubqueryTableSource_ptr tableSource = SQLSubqueryTableSource_ptr(new SQLSubqueryTableSource(select));
    stmt->setInto(tableSource);
    accept(Token::RPAREN);
  }
  else
  {
    stmt->setInto(exprParser->name());
  }

  stmt->getInto()->setAlias(tableAlias());

  if (lexer->identifierEquals(FnvHash::Constants::USING))
  {
    lexer->nextToken();
  }
  else
  {
    accept(Token::USING);
  }

  SQLTableSource_ptr using_ = this->createSQLSelectParser()->parseTableSource();
  stmt->setUsing(using_);

  accept(Token::ON);
  stmt->setOn(exprParser->expr());

  for (;;)
  {
    BOOL_ptr insertFlag = BOOL::FALSE;
    if (lexer->token()->name->c_str() == Token::WHEN.name->c_str())
    {
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::MATCHED.name->c_str() ||
          lexer->identifierEquals(FnvHash::Constants::MATCHED))
      {
        SQLMergeStatement_MergeUpdateClause_ptr updateClause = SQLMergeStatement_MergeUpdateClause_ptr(new SQLMergeStatement_MergeUpdateClause());
        lexer->nextToken();

        if (lexer->token()->name->c_str() == Token::AND.name->c_str())
        {
          lexer->nextToken();
          SQLExpr_ptr where = this->exprParser->expr();
          updateClause->setWhere(where);
        }

        accept(Token::THEN);
        if (lexer->token()->name->c_str() == Token::DELETE.name->c_str())
        {
          lexer->nextToken();
          updateClause->setDelete(BOOL::TRUE);
          stmt->setUpdateClause(updateClause);
          break;
        }

        accept(Token::UPDATE);
        accept(Token::SET);

        for (;;)
        {
          SQLUpdateSetItem_ptr item = this->exprParser->parseUpdateSetItem();

          updateClause->addItem(item);
          item->setParent(updateClause);

          if (lexer->token()->name->c_str() == (Token::COMMA.name->c_str()))
          {
            lexer->nextToken();
            continue;
          }

          break;
        }

        if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
        {
          lexer->nextToken();
          updateClause->setWhere(exprParser->expr());
        }

        // for hive

        SQLExpr_ptr deleteWhere = nullptr;
        if (lexer->token()->name->c_str() == Token::WHEN.name->c_str())
        {
          Lexer_SavePoint_ptr savePoint = lexer->mark();
          lexer->nextToken();
          if (lexer->token()->name->c_str() == Token::MATCHED.name->c_str())
          {
            lexer->nextToken();

            if (lexer->token()->name->c_str() == Token::AND.name->c_str())
            {
              lexer->nextToken();
              deleteWhere = this->exprParser->expr();
            }

            if (lexer->token()->name->c_str() == Token::THEN.name->c_str())
            {
              lexer->nextToken();

              if (lexer->token()->name->c_str() == Token::DELETE.name->c_str())
              {
                lexer->nextToken();
                updateClause->setDeleteWhere(deleteWhere);
              }
              else
              {
                deleteWhere = nullptr;
              }
            }
            else
            {
              deleteWhere = nullptr;
            }

            if (deleteWhere == nullptr)
            {
              lexer->reset(savePoint);
            }
          }
        }

        if (lexer->token()->name->c_str() == Token::DELETE.name->c_str())
        {
          lexer->nextToken();
          accept(Token::WHERE);
          updateClause->setDeleteWhere(exprParser->expr());
        }

        stmt->setUpdateClause(updateClause);
      }
      else if (lexer->token()->name->c_str() == Token::NOT.name->c_str())
      {
        lexer->nextToken();
        insertFlag = BOOL::TRUE;
      }
    }

    if (!insertFlag)
    {
      if (lexer->token()->name->c_str() == Token::WHEN.name->c_str())
      {
        lexer->nextToken();
      }

      if (lexer->token()->name->c_str() == Token::NOT.name->c_str())
      {
        lexer->nextToken();
        insertFlag = BOOL::TRUE;
      }
    }

    if (insertFlag)
    {
      SQLMergeStatement_MergeInsertClause_ptr insertClause = SQLMergeStatement_MergeInsertClause_ptr(new SQLMergeStatement_MergeInsertClause());

      if (lexer->identifierEquals(FnvHash::Constants::MATCHED))
      {
        lexer->nextToken();
      }
      else
      {
        accept(Token::MATCHED);
      }

      if (lexer->token()->name->c_str() == Token::AND.name->c_str())
      { // odps
        lexer->nextToken();
        insertClause->setWhere(this->exprParser->expr());
      }

      accept(Token::THEN);
      accept(Token::INSERT);

      if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
      {
        accept(Token::LPAREN);
        exprParser->exprList(insertClause->getColumns(), insertClause);
        accept(Token::RPAREN);
      }
      accept(Token::VALUES);
      accept(Token::LPAREN);
      exprParser->exprList(insertClause->getValues(), insertClause);
      accept(Token::RPAREN);

      if (lexer->token()->name->c_str() == Token::WHERE.name->c_str())
      {
        lexer->nextToken();
        insertClause->setWhere(exprParser->expr());
      }

      stmt->setInsertClause(insertClause);
    }

    if (lexer->token()->name->c_str() == Token::WHEN.name->c_str())
    {
      continue;
    }

    break;
  }

  SQLErrorLoggingClause_ptr errorClause = parseErrorLoggingClause();
  stmt->setErrorLoggingClause(errorClause);

  return stmt;
}
SQLErrorLoggingClause_ptr SQLStatementParser::parseErrorLoggingClause()
{
  if (lexer->identifierEquals(L"LOG"))
  {
    SQLErrorLoggingClause_ptr errorClause = SQLErrorLoggingClause_ptr(new SQLErrorLoggingClause());

    lexer->nextToken();
    accept(Token::ERRORS);
    if (lexer->token()->name->c_str() == Token::INTO.name->c_str())
    {
      lexer->nextToken();
      errorClause->setInto(exprParser->name());
    }

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
      errorClause->setSimpleExpression(exprParser->expr());
      accept(Token::RPAREN);
    }

    if (lexer->token()->name->c_str() == Token::REJECT.name->c_str())
    {
      lexer->nextToken();
      accept(Token::LIMIT);
      errorClause->setLimit(exprParser->expr());
    }

    return errorClause;
  }
  return nullptr;
}

SQLStatement_ptr SQLStatementParser::parseRefresh()
{
  if (lexer->identifierEquals(L"REFRESH"))
  {
    lexer->nextToken();
  }
  SQLRefreshMaterializedViewStatement_ptr stmt = SQLRefreshMaterializedViewStatement_ptr(new SQLRefreshMaterializedViewStatement());
  stmt->setDbType(dbType);

  acceptIdentifier("MATERIALIZED");

  if (lexer->identifierEquals(L"CONCURRENTLY"))
  {
    lexer->nextToken();
    stmt->setConcurrently(BOOL::TRUE);
  }
  accept(Token::VIEW);

  stmt->setName(this->exprParser->name());

  if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
  {
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() &&
        StringUtils::equalsIgnoreCase(make_string_ptr("NO"), make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()))))
    {
      lexer->nextToken();
      stmt->setWithNoData(BOOL::TRUE);
    }

    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() &&
        StringUtils::equalsIgnoreCase(make_string_ptr("DATA"), make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()))))
    {
      lexer->nextToken();
      stmt->setWithData(BOOL::TRUE);
    }
    else
    {
      std::string tmp = "syntax error, expect DATA, actual ";
      tmp += lexer->token()->name->c_str();
      tmp += ", pos ";
      tmp += std::to_string(lexer->pos());
      throw new ParserException(make_string_ptr(tmp));
    }
  }
  return stmt;
}

SQLFetchStatement_ptr SQLStatementParser::parseFetch()
{
  accept(Token::FETCH);

  SQLFetchStatement_ptr stmt = SQLFetchStatement_ptr(new SQLFetchStatement());
  stmt->setCursorName(this->exprParser->name());

  if (lexer->identifierEquals(L"BULK"))
  {
    lexer->nextToken();
    acceptIdentifier("COLLECT");
    stmt->setBulkCollect(BOOL::TRUE);
  }

  accept(Token::INTO);
  for (;;)
  {
    stmt->getInto()->push_back(this->exprParser->name());
    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }

    break;
  }

  if (lexer->token()->name->c_str() == Token::LIMIT.name->c_str())
  {
    SQLLimit_ptr limit = this->exprParser->parseLimit();
    stmt->setLimit(limit);
  }

  return stmt;
}

SQLOpenStatement_ptr SQLStatementParser::parseOpen()
{
  SQLOpenStatement_ptr stmt = SQLOpenStatement_ptr(new SQLOpenStatement());
  accept(Token::OPEN);

  SQLName_ptr cursorName;
  if (lexer->token()->name->c_str() == Token::QUES.name->c_str())
  {
    lexer->nextToken();
    cursorName = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr("?")));
  }
  else
  {
    cursorName = exprParser->name();
  }
  stmt->setCursorName(cursorName);

  if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    lexer->nextToken();
    this->exprParser->names(stmt->getColumns(), stmt);
    accept(Token::RPAREN);
  }

  if (lexer->token()->name->c_str() == Token::FOR.name->c_str())
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::SELECT.name->c_str())
    {
      SQLSelectParser_ptr selectParser = createSQLSelectParser();
      SQLSelect_ptr select = selectParser->select();
      SQLQueryExpr_ptr queryExpr = SQLQueryExpr_ptr(new SQLQueryExpr(select));
      stmt->setFor(queryExpr);
    }
    else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      string_ptr chars = make_string_ptr(encode_util::UnicodeToUTF8(lexer->stringVal_));
      SQLExprParser_ptr exprParser = SQLParserUtils::createExprParser(chars, dbType);
      SQLSelectParser_ptr selectParser = this->createSQLSelectParser(exprParser);
      SQLSelect_ptr select = selectParser->select();
      SQLQueryExpr_ptr queryExpr = SQLQueryExpr_ptr(new SQLQueryExpr(select));
      stmt->setFor(queryExpr);

      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::QUES.name->c_str())
    {
      lexer->nextToken();
      stmt->setFor(SQLVariantRefExpr_ptr(new SQLVariantRefExpr(make_string_ptr("?"))));
    }
    else
    {
      std::string tmp = "TODO ";
      tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
      throw new ParserException(make_string_ptr(tmp));
    }
  }

  if (lexer->token()->name->c_str() == Token::USING.name->c_str())
  {
    lexer->nextToken();
    this->exprParser->exprList(stmt->getUsing(), stmt);
  }

  accept(Token::SEMI);
  stmt->setAfterSemi(BOOL::TRUE);
  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseClose()
{
  SQLCloseStatement_ptr stmt = SQLCloseStatement_ptr(new SQLCloseStatement());
  accept(Token::CLOSE);
  stmt->setCursorName(exprParser->name());
  accept(Token::SEMI);
  stmt->setAfterSemi(BOOL::TRUE);
  return stmt;
}

SQLStatement_ptr SQLStatementParser::parseAlterIndex()
{
  accept(Token::ALTER);
  lexer->nextToken();
  SQLAlterIndexStatement_ptr stmt = SQLAlterIndexStatement_ptr(new SQLAlterIndexStatement());
  stmt->setName(this->exprParser->name());

  if (lexer->identifierEquals(L"RENAME"))
  {
    lexer->nextToken();
    accept(Token::TO);
    stmt->setRenameTo(this->exprParser->name());
  }

  if (lexer->token()->name->c_str() == Token::ON.name->c_str())
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
    {
      lexer->nextToken();
    }
    SQLName_ptr table = this->exprParser->name();
    stmt->setTable(table);
  }

  if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str())
  {
    lexer->nextToken();
    accept(Token::LPAREN);
    parseAssignItems(stmt->getPartitions(), stmt);
    accept(Token::RPAREN);
  }

  if (lexer->identifierEquals(FnvHash::Constants::DBPARTITION))
  {
    SQLPartitionBy_ptr partitionClause = this->getSQLCreateTableParser()->parsePartitionBy();
    stmt->setDbPartitionBy(partitionClause);
  }

  if (lexer->token()->name->c_str() == Token::ENABLE.name->c_str())
  {
    lexer->nextToken();
    stmt->setEnable(BOOL::TRUE);
  }

  if (lexer->token()->name->c_str() == Token::DISABLE.name->c_str())
  {
    lexer->nextToken();
    stmt->setEnable(BOOL::FALSE);
  }
  if (lexer->hashLCase_ == FnvHash::Constants::UNUSABLE)
  {
    lexer->nextToken();
    stmt->setUnusable(BOOL::TRUE);
  }

  for (;;)
  {
    if (lexer->identifierEquals(L"rebuild"))
    {
      lexer->nextToken();

      SQLAlterIndexStatement_Rebuild_ptr rebuild = SQLAlterIndexStatement_Rebuild_ptr(new SQLAlterIndexStatement_Rebuild());
      stmt->setRebuild(rebuild);
      continue;
    }
    else if (lexer->identifierEquals(L"MONITORING"))
    {
      lexer->nextToken();
      acceptIdentifier("USAGE");
      stmt->setMonitoringUsage(BOOL::TRUE);
      continue;
    }
    else if (lexer->identifierEquals(L"PARALLEL"))
    {
      lexer->nextToken();
      stmt->setParallel(this->exprParser->expr());
    }
    break;
  }

  return stmt;
}

SQLAlterSequenceStatement_ptr SQLStatementParser::parseAlterSequence()
{
  accept(Token::ALTER);

  accept(Token::SEQUENCE);

  SQLAlterSequenceStatement_ptr stmt = SQLAlterSequenceStatement_ptr(new SQLAlterSequenceStatement());
  stmt->setDbType(dbType);
  stmt->setName(this->exprParser->name());

  if (lexer->identifierEquals(FnvHash::Constants::CHANGE))
  {
    lexer->nextToken();
    accept(Token::TO);

    if (lexer->identifierEquals(FnvHash::Constants::SIMPLE))
    {
      stmt->setChangeToSimple(BOOL::TRUE);
      lexer->nextToken();
      if (lexer->hashLCase() == FnvHash::Constants::WITH)
      {
        lexer->nextToken();
        accept(Token::CACHE);
        stmt->setWithCache(BOOL::TRUE);
      }
    }
    else if (lexer->token()->name->c_str() == Token::GROUP.name->c_str())
    {
      stmt->setChangeToGroup(BOOL::TRUE);
      lexer->nextToken();
    }
    else if (lexer->identifierEquals(FnvHash::Constants::TIME))
    {
      stmt->setChangeToTime(BOOL::TRUE);
      lexer->nextToken();
    }
    else
    {
      std::string tmp = "TODO : ";
      tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
      throw new ParserException(make_string_ptr(tmp));
    }
  }

  for (;;)
  {
    if (lexer->token()->name->c_str() == Token::START.name->c_str() ||
        lexer->identifierEquals(FnvHash::Constants::START))
    {
      lexer->nextToken();
      accept(Token::WITH);
      stmt->setStartWith(this->exprParser->expr());
      continue;
    }
    else if (lexer->identifierEquals(L"INCREMENT"))
    {
      lexer->nextToken();
      accept(Token::BY);
      stmt->setIncrementBy(this->exprParser->expr());
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::CACHE.name->c_str())
    {
      lexer->nextToken();
      stmt->setCache(BOOL::TRUE);

      if (lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str() ||
          lexer->token()->name->c_str() == Token::QUES.name->c_str())
      {
        stmt->setCacheValue(this->exprParser->primary());
      }

      continue;
    }
    else if (lexer->token()->name->c_str() == Token::NOCACHE.name->c_str())
    {
      lexer->nextToken();
      stmt->setCache(BOOL::FALSE);
      continue;
    }
    else if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      lexer->nextToken();
      stmt->setOrder(BOOL::TRUE);
      continue;
    }
    else if (lexer->identifierEquals(FnvHash::Constants::RESTART))
    {
      lexer->nextToken();
      stmt->setRestart(BOOL::TRUE);

      if (lexer->token()->name->c_str() == Token::WITH.name->c_str() ||
          lexer->token()->name->c_str() == Token::EQ.name->c_str())
      {
        lexer->nextToken();
        stmt->setRestartWith(this->exprParser->primary());
      }
      else if (lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str())
      {
        stmt->setRestartWith(this->exprParser->primary());
      }

      continue;
    }
    else if (lexer->identifierEquals(L"NOORDER"))
    {
      lexer->nextToken();
      stmt->setOrder(BOOL::FALSE);
      continue;
    }
    else if (lexer->identifierEquals(L"CYCLE"))
    {
      lexer->nextToken();
      stmt->setCycle(BOOL::TRUE);
      continue;
    }
    else if (lexer->identifierEquals(L"NOCYCLE"))
    {
      lexer->nextToken();
      stmt->setCycle(BOOL::FALSE);
      continue;
    }
    else if (lexer->identifierEquals(L"MINVALUE"))
    {
      lexer->nextToken();
      stmt->setMinValue(this->exprParser->expr());
      continue;
    }
    else if (lexer->identifierEquals(L"MAXVALUE"))
    {
      lexer->nextToken();
      stmt->setMaxValue(this->exprParser->expr());
      continue;
    }
    else if (lexer->identifierEquals(L"NOMAXVALUE"))
    {
      lexer->nextToken();
      stmt->setNoMaxValue(BOOL::TRUE);
      continue;
    }
    else if (lexer->identifierEquals(L"NOMINVALUE"))
    {
      lexer->nextToken();
      stmt->setNoMinValue(BOOL::TRUE);
      continue;
    }
    break;
  }

  return stmt;
}

SQLAlterTableItem_ptr SQLStatementParser::parseAlterTableRename()
{
  acceptIdentifier("RENAME");

  if (lexer->token()->name->c_str() == Token::COLUMN.name->c_str())
  {
    lexer->nextToken();
    SQLAlterTableRenameColumn_ptr renameColumn = SQLAlterTableRenameColumn_ptr(new SQLAlterTableRenameColumn());
    renameColumn->setColumn(this->exprParser->name());
    accept(Token::TO);
    renameColumn->setTo(this->exprParser->name());
    return renameColumn;
  }
  else if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str())
  {
    lexer->nextToken();
    SQLAlterTableRenameConstraint_ptr renameConstraint = SQLAlterTableRenameConstraint_ptr(new SQLAlterTableRenameConstraint());
    renameConstraint->setConstraint(this->exprParser->name());
    accept(Token::TO);
    renameConstraint->setTo(this->exprParser->name());
    return renameConstraint;
  }

  if (lexer->token()->name->c_str() == Token::TO.name->c_str())
  {
    lexer->nextToken();
    SQLAlterTableRename_ptr item = SQLAlterTableRename_ptr(new SQLAlterTableRename());
    item->setTo(this->exprParser->name());
    return item;
  }

  std::string tmp = "TODO ";
  tmp += encode_util::UnicodeToUTF8(lexer->info()).c_str();
  throw new ParserException(make_string_ptr(tmp));
}

SQLPartitionRef_ptr SQLStatementParser::parsePartitionRef()
{
  accept(Token::PARTITION);

  SQLPartitionRef_ptr partitionRef = SQLPartitionRef_ptr(new SQLPartitionRef());

  accept(Token::LPAREN);

  for (;;)
  {
    SQLIdentifierExpr_ptr name = std::dynamic_pointer_cast<SQLIdentifierExpr>(this->exprParser->name());
    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr value = this->exprParser->expr();
      partitionRef->addItem(name, value);
    }
    else
    {
      partitionRef->addItem(SQLPartitionRef_Item_ptr(new SQLPartitionRef_Item(name)));
    }

    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    else
    {
      break;
    }
  }

  accept(Token::RPAREN);

  return partitionRef;
}